All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6
@ 2013-02-19 11:35 ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

The system reset controller (SRC) on i.MX51, i.MX53, and i.MX6q controls
reset lines to the GPU, VPU, IPU, and OpenVG IP modules.

The following patches add a simple API for devices to request being reset
by separate reset controller hardware and implements the reset signal
device tree binding proposed by Stephen Warren. Contrary to Tegra hardware,
the i.MX SRC contains self-deasserting reset registers, so I've included
both ops to manually assert/deassert a reset line, as well as a "reset"
operation that is supposed to assert the reset line and wait for it to
deassert.

The i.MX SRC is enhanced to provide a reset controller and the IPU driver
is made to request being reset by calling the device_reset(&pdev->dev)
convenience wrapper during probing.

Changes since v2:
 - Added ARCH_HAS_RESET_CONTROLLER to enable the reset controller API
   by default, where needed. Select it from HAVE_IMX_SRC.
 - Fixed kerneldoc comments.
 - Export reset_controller_(un)register
 - Simplified reset_control_get
 - Call reset_control_put in device_reset
 - Add locking around read-modify-write accesses to SCR_SRC
 - Renamed "gpios" device tree property to "reset-gpios" and added
   device tree binding documentation for gpio-reset.
 - Rebased onto next-20120219.

regards
Philipp

---
 .../devicetree/bindings/reset/fsl,imx-src.txt      |   49 +++++
 .../devicetree/bindings/reset/gpio-reset.txt       |   31 +++
 Documentation/devicetree/bindings/reset/reset.txt  |   75 +++++++
 .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    3 +
 arch/arm/boot/dts/imx51.dtsi                       |    7 +
 arch/arm/boot/dts/imx53.dtsi                       |    7 +
 arch/arm/boot/dts/imx6q.dtsi                       |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi                     |    4 +-
 arch/arm/mach-imx/Kconfig                          |    3 +
 arch/arm/mach-imx/mm-imx5.c                        |    2 +
 arch/arm/mach-imx/src.c                            |   68 +++++-
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    3 +
 drivers/reset/Kconfig                              |   26 +++
 drivers/reset/Makefile                             |    2 +
 drivers/reset/core.c                               |  220 ++++++++++++++++++++
 drivers/reset/gpio-reset.c                         |  189 +++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-common.c        |   12 +-
 include/linux/reset-controller.h                   |   43 ++++
 include/linux/reset.h                              |   17 ++
 20 files changed, 759 insertions(+), 5 deletions(-)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6
@ 2013-02-19 11:35 ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

The system reset controller (SRC) on i.MX51, i.MX53, and i.MX6q controls
reset lines to the GPU, VPU, IPU, and OpenVG IP modules.

The following patches add a simple API for devices to request being reset
by separate reset controller hardware and implements the reset signal
device tree binding proposed by Stephen Warren. Contrary to Tegra hardware,
the i.MX SRC contains self-deasserting reset registers, so I've included
both ops to manually assert/deassert a reset line, as well as a "reset"
operation that is supposed to assert the reset line and wait for it to
deassert.

The i.MX SRC is enhanced to provide a reset controller and the IPU driver
is made to request being reset by calling the device_reset(&pdev->dev)
convenience wrapper during probing.

Changes since v2:
 - Added ARCH_HAS_RESET_CONTROLLER to enable the reset controller API
   by default, where needed. Select it from HAVE_IMX_SRC.
 - Fixed kerneldoc comments.
 - Export reset_controller_(un)register
 - Simplified reset_control_get
 - Call reset_control_put in device_reset
 - Add locking around read-modify-write accesses to SCR_SRC
 - Renamed "gpios" device tree property to "reset-gpios" and added
   device tree binding documentation for gpio-reset.
 - Rebased onto next-20120219.

regards
Philipp

---
 .../devicetree/bindings/reset/fsl,imx-src.txt      |   49 +++++
 .../devicetree/bindings/reset/gpio-reset.txt       |   31 +++
 Documentation/devicetree/bindings/reset/reset.txt  |   75 +++++++
 .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    3 +
 arch/arm/boot/dts/imx51.dtsi                       |    7 +
 arch/arm/boot/dts/imx53.dtsi                       |    7 +
 arch/arm/boot/dts/imx6q.dtsi                       |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi                     |    4 +-
 arch/arm/mach-imx/Kconfig                          |    3 +
 arch/arm/mach-imx/mm-imx5.c                        |    2 +
 arch/arm/mach-imx/src.c                            |   68 +++++-
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    3 +
 drivers/reset/Kconfig                              |   26 +++
 drivers/reset/Makefile                             |    2 +
 drivers/reset/core.c                               |  220 ++++++++++++++++++++
 drivers/reset/gpio-reset.c                         |  189 +++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-common.c        |   12 +-
 include/linux/reset-controller.h                   |   43 ++++
 include/linux/reset.h                              |   17 ++
 20 files changed, 759 insertions(+), 5 deletions(-)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 1/8] dt: describe base reset signal binding
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Stephen Warren,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

From: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This binding is intended to represent the hardware reset signals present
internally in most IC (SoC, FPGA, ...) designs.
It consists of a binding for a reset controller device (provider), and a
pair of properties, "resets" and "reset-names", to link a device node
(consumer) to its reset controller via phandle, similarly to the clock
and interrupt bindings.

The reset controller has all information necessary to reset the consumer
device. That could be provided via device tree, or it could be implemented
in hardware.
The aim is to enable device drivers to request a framework API to issue a
reset simply by providing their struct device pointer as the most common
case.

Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 Documentation/devicetree/bindings/reset/reset.txt |   75 +++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/reset.txt

diff --git a/Documentation/devicetree/bindings/reset/reset.txt b/Documentation/devicetree/bindings/reset/reset.txt
new file mode 100644
index 0000000..31db6ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/reset.txt
@@ -0,0 +1,75 @@
+= Reset Signal Device Tree Bindings =
+
+This binding is intended to represent the hardware reset signals present
+internally in most IC (SoC, FPGA, ...) designs. Reset signals for whole
+standalone chips are most likely better represented as GPIOs, although there
+are likely to be exceptions to this rule.
+
+Hardware blocks typically receive a reset signal. This signal is generated by
+a reset provider (e.g. power management or clock module) and received by a
+reset consumer (the module being reset, or a module managing when a sub-
+ordinate module is reset). This binding exists to represent the provider and
+consumer, and provide a way to couple the two together.
+
+A reset signal is represented by the phandle of the provider, plus a reset
+specifier - a list of DT cells that represents the reset signal within the
+provider. The length (number of cells) and semantics of the reset specifier
+are dictated by the binding of the reset provider, although common schemes
+are described below.
+
+A word on where to place reset signal consumers in device tree: It is possible
+in hardware for a reset signal to affect multiple logically separate HW blocks
+at once. In this case, it would be unwise to represent this reset signal in
+the DT node of each affected HW block, since if activated, an unrelated block
+may be reset. Instead, reset signals should be represented in the DT node
+where it makes most sense to control it; this may be a bus node if all
+children of the bus are affected by the reset signal, or an individual HW
+block node for dedicated reset signals. The intent of this binding is to give
+appropriate software access to the reset signals in order to manage the HW,
+rather than to slavishly enumerate the reset signal that affects each HW
+block.
+
+= Reset providers =
+
+Required properties:
+#reset-cells:	Number of cells in a reset specifier; Typically 0 for nodes
+		with a single reset output and 1 for nodes with multiple
+		reset outputs.
+
+For example:
+
+	rst: reset-controller {
+		#reset-cells = <1>;
+	};
+
+= Reset consumers =
+
+Required properties:
+resets:		List of phandle and reset specifier pairs, one pair
+		for each reset signal that affects the device, or that the
+		device manages. Note: if the reset provider specifies '0' for
+		#reset-cells, then only the phandle portion of the pair will
+		appear.
+
+Optional properties:
+reset-names:	List of reset signal name strings sorted in the same order as
+		the resets property. Consumers drivers will use reset-names to
+		match reset signal names with reset specifiers.
+
+For example:
+
+	device {
+		resets = <&rst 20>;
+		reset-names = "reset";
+	};
+
+This represents a device with a single reset signal named "reset".
+
+	bus {
+		resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>;
+		reset-names = "i2s1", "i2s2", "dma", "mixer";
+	};
+
+This represents a bus that controls the reset signal of each of four sub-
+ordinate devices. Consider for example a bus that fails to operate unless no
+child device has reset asserted.
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 1/8] dt: describe base reset signal binding
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

From: Stephen Warren <swarren@nvidia.com>

This binding is intended to represent the hardware reset signals present
internally in most IC (SoC, FPGA, ...) designs.
It consists of a binding for a reset controller device (provider), and a
pair of properties, "resets" and "reset-names", to link a device node
(consumer) to its reset controller via phandle, similarly to the clock
and interrupt bindings.

The reset controller has all information necessary to reset the consumer
device. That could be provided via device tree, or it could be implemented
in hardware.
The aim is to enable device drivers to request a framework API to issue a
reset simply by providing their struct device pointer as the most common
case.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
---
 Documentation/devicetree/bindings/reset/reset.txt |   75 +++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/reset.txt

diff --git a/Documentation/devicetree/bindings/reset/reset.txt b/Documentation/devicetree/bindings/reset/reset.txt
new file mode 100644
index 0000000..31db6ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/reset.txt
@@ -0,0 +1,75 @@
+= Reset Signal Device Tree Bindings =
+
+This binding is intended to represent the hardware reset signals present
+internally in most IC (SoC, FPGA, ...) designs. Reset signals for whole
+standalone chips are most likely better represented as GPIOs, although there
+are likely to be exceptions to this rule.
+
+Hardware blocks typically receive a reset signal. This signal is generated by
+a reset provider (e.g. power management or clock module) and received by a
+reset consumer (the module being reset, or a module managing when a sub-
+ordinate module is reset). This binding exists to represent the provider and
+consumer, and provide a way to couple the two together.
+
+A reset signal is represented by the phandle of the provider, plus a reset
+specifier - a list of DT cells that represents the reset signal within the
+provider. The length (number of cells) and semantics of the reset specifier
+are dictated by the binding of the reset provider, although common schemes
+are described below.
+
+A word on where to place reset signal consumers in device tree: It is possible
+in hardware for a reset signal to affect multiple logically separate HW blocks
+at once. In this case, it would be unwise to represent this reset signal in
+the DT node of each affected HW block, since if activated, an unrelated block
+may be reset. Instead, reset signals should be represented in the DT node
+where it makes most sense to control it; this may be a bus node if all
+children of the bus are affected by the reset signal, or an individual HW
+block node for dedicated reset signals. The intent of this binding is to give
+appropriate software access to the reset signals in order to manage the HW,
+rather than to slavishly enumerate the reset signal that affects each HW
+block.
+
+= Reset providers =
+
+Required properties:
+#reset-cells:	Number of cells in a reset specifier; Typically 0 for nodes
+		with a single reset output and 1 for nodes with multiple
+		reset outputs.
+
+For example:
+
+	rst: reset-controller {
+		#reset-cells = <1>;
+	};
+
+= Reset consumers =
+
+Required properties:
+resets:		List of phandle and reset specifier pairs, one pair
+		for each reset signal that affects the device, or that the
+		device manages. Note: if the reset provider specifies '0' for
+		#reset-cells, then only the phandle portion of the pair will
+		appear.
+
+Optional properties:
+reset-names:	List of reset signal name strings sorted in the same order as
+		the resets property. Consumers drivers will use reset-names to
+		match reset signal names with reset specifiers.
+
+For example:
+
+	device {
+		resets = <&rst 20>;
+		reset-names = "reset";
+	};
+
+This represents a device with a single reset signal named "reset".
+
+	bus {
+		resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>;
+		reset-names = "i2s1", "i2s2", "dma", "mixer";
+	};
+
+This represents a bus that controls the reset signal of each of four sub-
+ordinate devices. Consider for example a bus that fails to operate unless no
+child device has reset asserted.
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

This adds a simple API for devices to request being reset
by separate reset controller hardware and implements the
reset signal device tree binding.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes since v2:
 - Added ARCH_HAS_RESET_CONTROLLER.
 - Fixed kerneldoc comments.
 - Export reset_controller_(un)register
 - Simplified reset_control_get
 - Call reset_control_put in device_reset
---
 drivers/Kconfig                  |    2 +
 drivers/Makefile                 |    3 +
 drivers/reset/Kconfig            |   13 +++
 drivers/reset/Makefile           |    1 +
 drivers/reset/core.c             |  220 ++++++++++++++++++++++++++++++++++++++
 include/linux/reset-controller.h |   43 ++++++++
 include/linux/reset.h            |   17 +++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/reset/Kconfig
 create mode 100644 drivers/reset/Makefile
 create mode 100644 drivers/reset/core.c
 create mode 100644 include/linux/reset-controller.h
 create mode 100644 include/linux/reset.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 202fa6d..847f8e3 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -162,4 +162,6 @@ source "drivers/irqchip/Kconfig"
 
 source "drivers/ipack/Kconfig"
 
+source "drivers/reset/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4af933d..682fb7c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -42,6 +42,9 @@ ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 obj-y				+= clocksource/
 endif
 
+# reset controllers early, since gpu drivers might rely on them to initialize
+obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
+
 # tty/ comes before char/ so that the VT console is the boot-time
 # default.
 obj-y				+= tty/
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
new file mode 100644
index 0000000..c9d04f7
--- /dev/null
+++ b/drivers/reset/Kconfig
@@ -0,0 +1,13 @@
+config ARCH_HAS_RESET_CONTROLLER
+	bool
+
+menuconfig RESET_CONTROLLER
+	bool "Reset Controller Support"
+	default y if ARCH_HAS_RESET_CONTROLLER
+	help
+	  Generic Reset Controller support.
+
+	  This framework is designed to abstract reset handling of devices
+	  via GPIOs or SoC-internal reset controller modules.
+
+	  If unsure, say no.
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
new file mode 100644
index 0000000..1e2d83f
--- /dev/null
+++ b/drivers/reset/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RESET_CONTROLLER) += core.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
new file mode 100644
index 0000000..d2fe357
--- /dev/null
+++ b/drivers/reset/core.c
@@ -0,0 +1,220 @@
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(reset_controller_list_mutex);
+static LIST_HEAD(reset_controller_list);
+
+/**
+ * struct reset_control - a reset control
+ * @rcdev: a pointer to the reset controller device
+ *         this reset control belongs to
+ * @id: ID of the reset controller in the reset
+ *      controller device
+ */
+struct reset_control {
+	struct reset_controller_dev *rcdev;
+	unsigned int id;
+};
+
+/**
+ * reset_controller_register - register a reset controller device
+ * @rcdev: a pointer to the initialized reset controller device
+ */
+int reset_controller_register(struct reset_controller_dev *rcdev)
+{
+	mutex_lock(&reset_controller_list_mutex);
+	list_add(&rcdev->list, &reset_controller_list);
+	mutex_unlock(&reset_controller_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(reset_controller_register);
+
+/**
+ * reset_controller_unregister - unregister a reset controller device
+ * @rcdev: a pointer to the reset controller device
+ */
+void reset_controller_unregister(struct reset_controller_dev *rcdev)
+{
+	mutex_lock(&reset_controller_list_mutex);
+	list_del(&rcdev->list);
+	mutex_unlock(&reset_controller_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_controller_unregister);
+
+/**
+ * reset_control_reset - reset the controlled device
+ * @rstc: reset controller
+ */
+int reset_control_reset(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->reset)
+		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_reset);
+
+/**
+ * reset_control_assert - asserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_assert(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->assert)
+		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_assert);
+
+/**
+ * reset_control_deassert - deasserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_deassert(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->deassert)
+		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_deassert);
+
+/**
+ * reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @dev: 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 *reset_control_get(struct device *dev, const char *id)
+{
+	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+	struct reset_controller_dev *r, *rcdev;
+	struct of_phandle_args args;
+	int index = 0;
+	int ret;
+
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	if (id)
+		index = of_property_match_string(dev->of_node,
+						 "reset-names", id);
+	ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells",
+					 index, &args);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mutex_lock(&reset_controller_list_mutex);
+	rcdev = NULL;
+	list_for_each_entry(r, &reset_controller_list, list) {
+		if (args.np == r->of_node) {
+			rcdev = r;
+			break;
+		}
+	}
+	mutex_unlock(&reset_controller_list_mutex);
+	of_node_put(args.np);
+
+	if (!rcdev)
+		return ERR_PTR(-ENODEV);
+
+	try_module_get(rcdev->owner);
+
+	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+	if (!rstc)
+		return ERR_PTR(-ENOMEM);
+
+	rstc->rcdev = rcdev;
+	rstc->id = args.args[0];
+
+	return rstc;
+}
+EXPORT_SYMBOL_GPL(reset_control_get);
+
+/**
+ * reset_control_put - free the reset controller
+ * @rstc: reset controller
+ */
+
+void reset_control_put(struct reset_control *rstc)
+{
+	if (IS_ERR(rstc))
+		return;
+
+	module_put(rstc->rcdev->owner);
+	kfree(rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_put);
+
+static void devm_reset_control_release(struct device *dev, void *res)
+{
+	reset_control_put(*(struct reset_control **)res);
+}
+
+/**
+ * devm_reset_control_get - resource managed reset_control_get()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get(). For reset controllers returned from this
+ * function, reset_control_put() is called automatically on driver detach.
+ * See reset_control_get() for more information.
+ */
+struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
+{
+	struct reset_control **ptr, *rstc;
+
+	ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	rstc = reset_control_get(dev, id);
+	if (!IS_ERR(rstc)) {
+		*ptr = rstc;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return rstc;
+}
+EXPORT_SYMBOL_GPL(devm_reset_control_get);
+
+/**
+ * device_reset - find reset controller associated with the device
+ *                and perform reset
+ * @dev: device to be reset by the controller
+ *
+ * Convenience wrapper for reset_control_get() and reset_control_reset().
+ * This is useful for the common case of devices with single, dedicated reset
+ * lines.
+ */
+int device_reset(struct device *dev)
+{
+	struct reset_control *rstc;
+	int ret;
+
+	rstc = reset_control_get(dev, NULL);
+	if (IS_ERR(rstc))
+		return PTR_ERR(rstc);
+
+	ret = reset_control_reset(rstc);
+
+	reset_control_put(rstc);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(device_reset);
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
new file mode 100644
index 0000000..ce5c8c0
--- /dev/null
+++ b/include/linux/reset-controller.h
@@ -0,0 +1,43 @@
+#ifndef _LINUX_RESET_CONTROLLER_H_
+#define _LINUX_RESET_CONTROLLER_H_
+
+#include <linux/list.h>
+
+struct reset_controller_dev;
+
+/**
+ * struct reset_control_ops
+ *
+ * @reset: for self-deasserting resets, does all necessary
+ *         things to reset the device
+ * @assert: manually assert the reset line, if supported
+ * @deassert: manually deassert the reset line, if supported
+ */
+struct reset_control_ops {
+	int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);
+};
+
+struct module;
+struct device_node;
+
+/**
+ * struct reset_controller_dev - reset controller entity that might
+ *                               provide multiple reset controls
+ * @ops: a pointer to device specific struct reset_control_ops
+ * @owner: kernel module of the reset controller driver
+ * @list: internal list of reset controller devices
+ * @of_node: corresponding device tree node as phandle target
+ */
+struct reset_controller_dev {
+	struct reset_control_ops *ops;
+	struct module *owner;
+	struct list_head list;
+	struct device_node *of_node;
+};
+
+int reset_controller_register(struct reset_controller_dev *rcdev);
+void reset_controller_unregister(struct reset_controller_dev *rcdev);
+
+#endif
diff --git a/include/linux/reset.h b/include/linux/reset.h
new file mode 100644
index 0000000..6082247
--- /dev/null
+++ b/include/linux/reset.h
@@ -0,0 +1,17 @@
+#ifndef _LINUX_RESET_H_
+#define _LINUX_RESET_H_
+
+struct device;
+struct reset_control;
+
+int reset_control_reset(struct reset_control *rstc);
+int reset_control_assert(struct reset_control *rstc);
+int reset_control_deassert(struct reset_control *rstc);
+
+struct reset_control *reset_control_get(struct device *dev, const char *id);
+void reset_control_put(struct reset_control *rstc);
+struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
+
+int device_reset(struct device *dev);
+
+#endif
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a simple API for devices to request being reset
by separate reset controller hardware and implements the
reset signal device tree binding.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
Changes since v2:
 - Added ARCH_HAS_RESET_CONTROLLER.
 - Fixed kerneldoc comments.
 - Export reset_controller_(un)register
 - Simplified reset_control_get
 - Call reset_control_put in device_reset
---
 drivers/Kconfig                  |    2 +
 drivers/Makefile                 |    3 +
 drivers/reset/Kconfig            |   13 +++
 drivers/reset/Makefile           |    1 +
 drivers/reset/core.c             |  220 ++++++++++++++++++++++++++++++++++++++
 include/linux/reset-controller.h |   43 ++++++++
 include/linux/reset.h            |   17 +++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/reset/Kconfig
 create mode 100644 drivers/reset/Makefile
 create mode 100644 drivers/reset/core.c
 create mode 100644 include/linux/reset-controller.h
 create mode 100644 include/linux/reset.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 202fa6d..847f8e3 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -162,4 +162,6 @@ source "drivers/irqchip/Kconfig"
 
 source "drivers/ipack/Kconfig"
 
+source "drivers/reset/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4af933d..682fb7c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -42,6 +42,9 @@ ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 obj-y				+= clocksource/
 endif
 
+# reset controllers early, since gpu drivers might rely on them to initialize
+obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
+
 # tty/ comes before char/ so that the VT console is the boot-time
 # default.
 obj-y				+= tty/
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
new file mode 100644
index 0000000..c9d04f7
--- /dev/null
+++ b/drivers/reset/Kconfig
@@ -0,0 +1,13 @@
+config ARCH_HAS_RESET_CONTROLLER
+	bool
+
+menuconfig RESET_CONTROLLER
+	bool "Reset Controller Support"
+	default y if ARCH_HAS_RESET_CONTROLLER
+	help
+	  Generic Reset Controller support.
+
+	  This framework is designed to abstract reset handling of devices
+	  via GPIOs or SoC-internal reset controller modules.
+
+	  If unsure, say no.
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
new file mode 100644
index 0000000..1e2d83f
--- /dev/null
+++ b/drivers/reset/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RESET_CONTROLLER) += core.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
new file mode 100644
index 0000000..d2fe357
--- /dev/null
+++ b/drivers/reset/core.c
@@ -0,0 +1,220 @@
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(reset_controller_list_mutex);
+static LIST_HEAD(reset_controller_list);
+
+/**
+ * struct reset_control - a reset control
+ * @rcdev: a pointer to the reset controller device
+ *         this reset control belongs to
+ * @id: ID of the reset controller in the reset
+ *      controller device
+ */
+struct reset_control {
+	struct reset_controller_dev *rcdev;
+	unsigned int id;
+};
+
+/**
+ * reset_controller_register - register a reset controller device
+ * @rcdev: a pointer to the initialized reset controller device
+ */
+int reset_controller_register(struct reset_controller_dev *rcdev)
+{
+	mutex_lock(&reset_controller_list_mutex);
+	list_add(&rcdev->list, &reset_controller_list);
+	mutex_unlock(&reset_controller_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(reset_controller_register);
+
+/**
+ * reset_controller_unregister - unregister a reset controller device
+ * @rcdev: a pointer to the reset controller device
+ */
+void reset_controller_unregister(struct reset_controller_dev *rcdev)
+{
+	mutex_lock(&reset_controller_list_mutex);
+	list_del(&rcdev->list);
+	mutex_unlock(&reset_controller_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_controller_unregister);
+
+/**
+ * reset_control_reset - reset the controlled device
+ * @rstc: reset controller
+ */
+int reset_control_reset(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->reset)
+		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_reset);
+
+/**
+ * reset_control_assert - asserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_assert(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->assert)
+		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_assert);
+
+/**
+ * reset_control_deassert - deasserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_deassert(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->deassert)
+		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_deassert);
+
+/**
+ * reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @dev: 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 *reset_control_get(struct device *dev, const char *id)
+{
+	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+	struct reset_controller_dev *r, *rcdev;
+	struct of_phandle_args args;
+	int index = 0;
+	int ret;
+
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+
+	if (id)
+		index = of_property_match_string(dev->of_node,
+						 "reset-names", id);
+	ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells",
+					 index, &args);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mutex_lock(&reset_controller_list_mutex);
+	rcdev = NULL;
+	list_for_each_entry(r, &reset_controller_list, list) {
+		if (args.np == r->of_node) {
+			rcdev = r;
+			break;
+		}
+	}
+	mutex_unlock(&reset_controller_list_mutex);
+	of_node_put(args.np);
+
+	if (!rcdev)
+		return ERR_PTR(-ENODEV);
+
+	try_module_get(rcdev->owner);
+
+	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+	if (!rstc)
+		return ERR_PTR(-ENOMEM);
+
+	rstc->rcdev = rcdev;
+	rstc->id = args.args[0];
+
+	return rstc;
+}
+EXPORT_SYMBOL_GPL(reset_control_get);
+
+/**
+ * reset_control_put - free the reset controller
+ * @rstc: reset controller
+ */
+
+void reset_control_put(struct reset_control *rstc)
+{
+	if (IS_ERR(rstc))
+		return;
+
+	module_put(rstc->rcdev->owner);
+	kfree(rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_put);
+
+static void devm_reset_control_release(struct device *dev, void *res)
+{
+	reset_control_put(*(struct reset_control **)res);
+}
+
+/**
+ * devm_reset_control_get - resource managed reset_control_get()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get(). For reset controllers returned from this
+ * function, reset_control_put() is called automatically on driver detach.
+ * See reset_control_get() for more information.
+ */
+struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
+{
+	struct reset_control **ptr, *rstc;
+
+	ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	rstc = reset_control_get(dev, id);
+	if (!IS_ERR(rstc)) {
+		*ptr = rstc;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return rstc;
+}
+EXPORT_SYMBOL_GPL(devm_reset_control_get);
+
+/**
+ * device_reset - find reset controller associated with the device
+ *                and perform reset
+ * @dev: device to be reset by the controller
+ *
+ * Convenience wrapper for reset_control_get() and reset_control_reset().
+ * This is useful for the common case of devices with single, dedicated reset
+ * lines.
+ */
+int device_reset(struct device *dev)
+{
+	struct reset_control *rstc;
+	int ret;
+
+	rstc = reset_control_get(dev, NULL);
+	if (IS_ERR(rstc))
+		return PTR_ERR(rstc);
+
+	ret = reset_control_reset(rstc);
+
+	reset_control_put(rstc);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(device_reset);
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
new file mode 100644
index 0000000..ce5c8c0
--- /dev/null
+++ b/include/linux/reset-controller.h
@@ -0,0 +1,43 @@
+#ifndef _LINUX_RESET_CONTROLLER_H_
+#define _LINUX_RESET_CONTROLLER_H_
+
+#include <linux/list.h>
+
+struct reset_controller_dev;
+
+/**
+ * struct reset_control_ops
+ *
+ * @reset: for self-deasserting resets, does all necessary
+ *         things to reset the device
+ * @assert: manually assert the reset line, if supported
+ * @deassert: manually deassert the reset line, if supported
+ */
+struct reset_control_ops {
+	int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);
+};
+
+struct module;
+struct device_node;
+
+/**
+ * struct reset_controller_dev - reset controller entity that might
+ *                               provide multiple reset controls
+ * @ops: a pointer to device specific struct reset_control_ops
+ * @owner: kernel module of the reset controller driver
+ * @list: internal list of reset controller devices
+ * @of_node: corresponding device tree node as phandle target
+ */
+struct reset_controller_dev {
+	struct reset_control_ops *ops;
+	struct module *owner;
+	struct list_head list;
+	struct device_node *of_node;
+};
+
+int reset_controller_register(struct reset_controller_dev *rcdev);
+void reset_controller_unregister(struct reset_controller_dev *rcdev);
+
+#endif
diff --git a/include/linux/reset.h b/include/linux/reset.h
new file mode 100644
index 0000000..6082247
--- /dev/null
+++ b/include/linux/reset.h
@@ -0,0 +1,17 @@
+#ifndef _LINUX_RESET_H_
+#define _LINUX_RESET_H_
+
+struct device;
+struct reset_control;
+
+int reset_control_reset(struct reset_control *rstc);
+int reset_control_assert(struct reset_control *rstc);
+int reset_control_deassert(struct reset_control *rstc);
+
+struct reset_control *reset_control_get(struct device *dev, const char *id);
+void reset_control_put(struct reset_control *rstc);
+struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
+
+int device_reset(struct device *dev);
+
+#endif
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 3/8] ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC)
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

The SRC has auto-deasserting reset bits that control reset lines to
the GPU, VPU, IPU, and OpenVG IP modules. This patch adds a reset
controller that can be controlled by those devices using the
reset controller API.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes since v2:
 - Select ARCH_HAS_RESET_CONTROLLER from HAVE_IMX_SRC
 - Add locking around read-modify-write accesses to SCR_SRC
---
 .../devicetree/bindings/reset/fsl,imx-src.txt      |   49 +++++++++++++++
 arch/arm/mach-imx/Kconfig                          |    1 +
 arch/arm/mach-imx/src.c                            |   64 ++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/fsl,imx-src.txt

diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
new file mode 100644
index 0000000..1330177
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
@@ -0,0 +1,49 @@
+Freescale i.MX System Reset Controller
+======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "fsl,<chip>-src"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
+  in this order.
+- #reset-cells: 1, see below
+
+example:
+
+src: src@020d8000 {
+        compatible = "fsl,imx6q-src";
+        reg = <0x020d8000 0x4000>;
+        interrupts = <0 91 0x04 0 96 0x04>;
+        #reset-cells = <1>;
+};
+
+Specifying reset lines connected to IP modules
+==============================================
+
+The system reset controller can be used to reset the GPU, VPU,
+IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
+nodes should specify the reset line on the SRC in their resets
+property, containing a phandle to the SRC device node and a
+RESET_INDEX specifying which module to reset, as described in
+reset.txt
+
+example:
+
+        ipu1: ipu@02400000 {
+                resets = <&src 2>;
+        };
+        ipu2: ipu@02800000 {
+                resets = <&src 4>;
+        };
+
+The following RESET_INDEX values are valid for i.MX5:
+GPU_RESET     0
+VPU_RESET     1
+IPU1_RESET    2
+OPEN_VG_RESET 3
+The following additional RESET_INDEX value is valid for i.MX6:
+IPU2_RESET    4
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4c9c6f9..5052e31 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -73,6 +73,7 @@ config HAVE_IMX_MMDC
 
 config HAVE_IMX_SRC
 	def_bool y if SMP
+	select ARCH_HAS_RESET_CONTROLLER
 
 config IMX_HAVE_IOMUX_V1
 	bool
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index e15f155..3a39daf 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -14,16 +14,71 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/reset-controller.h>
 #include <linux/smp.h>
 #include <asm/smp_plat.h>
 
 #define SRC_SCR				0x000
 #define SRC_GPR1			0x020
 #define BP_SRC_SCR_WARM_RESET_ENABLE	0
+#define BP_SRC_SCR_SW_GPU_RST		1
+#define BP_SRC_SCR_SW_VPU_RST		2
+#define BP_SRC_SCR_SW_IPU1_RST		3
+#define BP_SRC_SCR_SW_OPEN_VG_RST	4
+#define BP_SRC_SCR_SW_IPU2_RST		12
 #define BP_SRC_SCR_CORE1_RST		14
 #define BP_SRC_SCR_CORE1_ENABLE		22
 
 static void __iomem *src_base;
+static DEFINE_SPINLOCK(scr_lock);
+
+static const int sw_reset_bits[5] = {
+	BP_SRC_SCR_SW_GPU_RST,
+	BP_SRC_SCR_SW_VPU_RST,
+	BP_SRC_SCR_SW_IPU1_RST,
+	BP_SRC_SCR_SW_OPEN_VG_RST,
+	BP_SRC_SCR_SW_IPU2_RST
+};
+
+static int imx_src_reset(struct reset_controller_dev *rcdev,
+		unsigned long sw_reset_idx)
+{
+	unsigned long timeout;
+	unsigned long flags;
+	int bit;
+	u32 val;
+
+	if (!src_base)
+		return -ENODEV;
+
+	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
+		return -EINVAL;
+
+	bit = 1 << sw_reset_bits[sw_reset_idx];
+
+	spin_lock_irqsave(&scr_lock, flags);
+	val = readl_relaxed(src_base + SRC_SCR);
+	val |= bit;
+	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock_irqrestore(&scr_lock, flags);
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (readl(src_base + SRC_SCR) & bit) {
+		if (time_after(jiffies, timeout))
+			return -ETIME;
+		cpu_relax();
+	}
+
+	return 0;
+}
+
+static struct reset_control_ops imx_src_ops = {
+	.reset = imx_src_reset,
+};
+
+static struct reset_controller_dev imx_reset_controller = {
+	.ops = &imx_src_ops,
+};
 
 void imx_enable_cpu(int cpu, bool enable)
 {
@@ -31,9 +86,11 @@ void imx_enable_cpu(int cpu, bool enable)
 
 	cpu = cpu_logical_map(cpu);
 	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val = enable ? val | mask : val & ~mask;
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 }
 
 void imx_set_cpu_jump(int cpu, void *jump_addr)
@@ -48,9 +105,11 @@ void imx_src_prepare_restart(void)
 	u32 val;
 
 	/* clear enable bits of secondary cores */
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 
 	/* clear persistent entry register of primary core */
 	writel_relaxed(0, src_base + SRC_GPR1);
@@ -65,11 +124,16 @@ void __init imx_src_init(void)
 	src_base = of_iomap(np, 0);
 	WARN_ON(!src_base);
 
+	imx_reset_controller.of_node = np;
+	reset_controller_register(&imx_reset_controller);
+
 	/*
 	 * force warm reset sources to generate cold reset
 	 * for a more reliable restart
 	 */
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 3/8] ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC)
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

The SRC has auto-deasserting reset bits that control reset lines to
the GPU, VPU, IPU, and OpenVG IP modules. This patch adds a reset
controller that can be controlled by those devices using the
reset controller API.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
Changes since v2:
 - Select ARCH_HAS_RESET_CONTROLLER from HAVE_IMX_SRC
 - Add locking around read-modify-write accesses to SCR_SRC
---
 .../devicetree/bindings/reset/fsl,imx-src.txt      |   49 +++++++++++++++
 arch/arm/mach-imx/Kconfig                          |    1 +
 arch/arm/mach-imx/src.c                            |   64 ++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/fsl,imx-src.txt

diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
new file mode 100644
index 0000000..1330177
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
@@ -0,0 +1,49 @@
+Freescale i.MX System Reset Controller
+======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "fsl,<chip>-src"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
+  in this order.
+- #reset-cells: 1, see below
+
+example:
+
+src: src at 020d8000 {
+        compatible = "fsl,imx6q-src";
+        reg = <0x020d8000 0x4000>;
+        interrupts = <0 91 0x04 0 96 0x04>;
+        #reset-cells = <1>;
+};
+
+Specifying reset lines connected to IP modules
+==============================================
+
+The system reset controller can be used to reset the GPU, VPU,
+IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
+nodes should specify the reset line on the SRC in their resets
+property, containing a phandle to the SRC device node and a
+RESET_INDEX specifying which module to reset, as described in
+reset.txt
+
+example:
+
+        ipu1: ipu at 02400000 {
+                resets = <&src 2>;
+        };
+        ipu2: ipu at 02800000 {
+                resets = <&src 4>;
+        };
+
+The following RESET_INDEX values are valid for i.MX5:
+GPU_RESET     0
+VPU_RESET     1
+IPU1_RESET    2
+OPEN_VG_RESET 3
+The following additional RESET_INDEX value is valid for i.MX6:
+IPU2_RESET    4
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4c9c6f9..5052e31 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -73,6 +73,7 @@ config HAVE_IMX_MMDC
 
 config HAVE_IMX_SRC
 	def_bool y if SMP
+	select ARCH_HAS_RESET_CONTROLLER
 
 config IMX_HAVE_IOMUX_V1
 	bool
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index e15f155..3a39daf 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -14,16 +14,71 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/reset-controller.h>
 #include <linux/smp.h>
 #include <asm/smp_plat.h>
 
 #define SRC_SCR				0x000
 #define SRC_GPR1			0x020
 #define BP_SRC_SCR_WARM_RESET_ENABLE	0
+#define BP_SRC_SCR_SW_GPU_RST		1
+#define BP_SRC_SCR_SW_VPU_RST		2
+#define BP_SRC_SCR_SW_IPU1_RST		3
+#define BP_SRC_SCR_SW_OPEN_VG_RST	4
+#define BP_SRC_SCR_SW_IPU2_RST		12
 #define BP_SRC_SCR_CORE1_RST		14
 #define BP_SRC_SCR_CORE1_ENABLE		22
 
 static void __iomem *src_base;
+static DEFINE_SPINLOCK(scr_lock);
+
+static const int sw_reset_bits[5] = {
+	BP_SRC_SCR_SW_GPU_RST,
+	BP_SRC_SCR_SW_VPU_RST,
+	BP_SRC_SCR_SW_IPU1_RST,
+	BP_SRC_SCR_SW_OPEN_VG_RST,
+	BP_SRC_SCR_SW_IPU2_RST
+};
+
+static int imx_src_reset(struct reset_controller_dev *rcdev,
+		unsigned long sw_reset_idx)
+{
+	unsigned long timeout;
+	unsigned long flags;
+	int bit;
+	u32 val;
+
+	if (!src_base)
+		return -ENODEV;
+
+	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
+		return -EINVAL;
+
+	bit = 1 << sw_reset_bits[sw_reset_idx];
+
+	spin_lock_irqsave(&scr_lock, flags);
+	val = readl_relaxed(src_base + SRC_SCR);
+	val |= bit;
+	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock_irqrestore(&scr_lock, flags);
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (readl(src_base + SRC_SCR) & bit) {
+		if (time_after(jiffies, timeout))
+			return -ETIME;
+		cpu_relax();
+	}
+
+	return 0;
+}
+
+static struct reset_control_ops imx_src_ops = {
+	.reset = imx_src_reset,
+};
+
+static struct reset_controller_dev imx_reset_controller = {
+	.ops = &imx_src_ops,
+};
 
 void imx_enable_cpu(int cpu, bool enable)
 {
@@ -31,9 +86,11 @@ void imx_enable_cpu(int cpu, bool enable)
 
 	cpu = cpu_logical_map(cpu);
 	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val = enable ? val | mask : val & ~mask;
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 }
 
 void imx_set_cpu_jump(int cpu, void *jump_addr)
@@ -48,9 +105,11 @@ void imx_src_prepare_restart(void)
 	u32 val;
 
 	/* clear enable bits of secondary cores */
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 
 	/* clear persistent entry register of primary core */
 	writel_relaxed(0, src_base + SRC_GPR1);
@@ -65,11 +124,16 @@ void __init imx_src_init(void)
 	src_base = of_iomap(np, 0);
 	WARN_ON(!src_base);
 
+	imx_reset_controller.of_node = np;
+	reset_controller_register(&imx_reset_controller);
+
 	/*
 	 * force warm reset sources to generate cold reset
 	 * for a more reliable restart
 	 */
+	spin_lock(&scr_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
 	writel_relaxed(val, src_base + SRC_SCR);
+	spin_unlock(&scr_lock);
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 4/8] ARM i.MX6q: Link system reset controller (SRC) to IPU in DT
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes since v2:
 - Rebased onto next-20120219
---
 arch/arm/boot/dts/imx6q.dtsi   |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi |    2 ++
 2 files changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index cba021e..4cd4f8d 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -291,6 +291,7 @@
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
+			resets = <&src 4>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 06ec460..3e21e92 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -516,6 +516,7 @@
 				compatible = "fsl,imx6q-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 0x04 0 96 0x04>;
+				#reset-cells = <1>;
 			};
 
 			gpc: gpc@020dc000 {
@@ -795,6 +796,7 @@
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
+			resets = <&src 2>;
 		};
 	};
 };
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 4/8] ARM i.MX6q: Link system reset controller (SRC) to IPU in DT
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
Changes since v2:
 - Rebased onto next-20120219
---
 arch/arm/boot/dts/imx6q.dtsi   |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi |    2 ++
 2 files changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index cba021e..4cd4f8d 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -291,6 +291,7 @@
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
+			resets = <&src 4>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 06ec460..3e21e92 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -516,6 +516,7 @@
 				compatible = "fsl,imx6q-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 0x04 0 96 0x04>;
+				#reset-cells = <1>;
 			};
 
 			gpc: gpc at 020dc000 {
@@ -795,6 +796,7 @@
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
+			resets = <&src 2>;
 		};
 	};
 };
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 5/8] staging: drm/imx: Use SRC to reset IPU
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Request the System Reset Controller to reset the IPU if
specified via device tree phandle.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 .../devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt    |    3 +++
 drivers/staging/imx-drm/ipu-v3/ipu-common.c                |   12 +++++++++---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index 07654f0..f769857 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -8,6 +8,8 @@ Required properties:
 - interrupts: Should contain sync interrupt and error interrupt,
   in this order.
 - #crtc-cells: 1, See below
+- resets: phandle pointing to the system reset controller and
+          reset line index, see reset/fsl,imx-src.txt for details
 
 example:
 
@@ -16,6 +18,7 @@ ipu: ipu@18000000 {
 	compatible = "fsl,imx53-ipu";
 	reg = <0x18000000 0x080000000>;
 	interrupts = <11 10>;
+	resets = <&src 2>;
 };
 
 Parallel display support
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 366f259..04b8320 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -16,6 +16,7 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/reset.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
@@ -660,7 +661,7 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
 
-static int ipu_reset(struct ipu_soc *ipu)
+static int ipu_memory_reset(struct ipu_soc *ipu)
 {
 	unsigned long timeout;
 
@@ -1104,7 +1105,12 @@ static int ipu_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_failed_irq;
 
-	ret = ipu_reset(ipu);
+	ret = device_reset(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+		goto out_failed_reset;
+	}
+	ret = ipu_memory_reset(ipu);
 	if (ret)
 		goto out_failed_reset;
 
@@ -1130,8 +1136,8 @@ static int ipu_probe(struct platform_device *pdev)
 failed_add_clients:
 	ipu_submodules_exit(ipu);
 failed_submodules_init:
-	ipu_irq_exit(ipu);
 out_failed_reset:
+	ipu_irq_exit(ipu);
 out_failed_irq:
 	clk_disable_unprepare(ipu->clk);
 failed_clk_get:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 5/8] staging: drm/imx: Use SRC to reset IPU
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Request the System Reset Controller to reset the IPU if
specified via device tree phandle.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
 .../devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt    |    3 +++
 drivers/staging/imx-drm/ipu-v3/ipu-common.c                |   12 +++++++++---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index 07654f0..f769857 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -8,6 +8,8 @@ Required properties:
 - interrupts: Should contain sync interrupt and error interrupt,
   in this order.
 - #crtc-cells: 1, See below
+- resets: phandle pointing to the system reset controller and
+          reset line index, see reset/fsl,imx-src.txt for details
 
 example:
 
@@ -16,6 +18,7 @@ ipu: ipu at 18000000 {
 	compatible = "fsl,imx53-ipu";
 	reg = <0x18000000 0x080000000>;
 	interrupts = <11 10>;
+	resets = <&src 2>;
 };
 
 Parallel display support
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 366f259..04b8320 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -16,6 +16,7 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/reset.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
@@ -660,7 +661,7 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
 
-static int ipu_reset(struct ipu_soc *ipu)
+static int ipu_memory_reset(struct ipu_soc *ipu)
 {
 	unsigned long timeout;
 
@@ -1104,7 +1105,12 @@ static int ipu_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_failed_irq;
 
-	ret = ipu_reset(ipu);
+	ret = device_reset(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+		goto out_failed_reset;
+	}
+	ret = ipu_memory_reset(ipu);
 	if (ret)
 		goto out_failed_reset;
 
@@ -1130,8 +1136,8 @@ static int ipu_probe(struct platform_device *pdev)
 failed_add_clients:
 	ipu_submodules_exit(ipu);
 failed_submodules_init:
-	ipu_irq_exit(ipu);
 out_failed_reset:
+	ipu_irq_exit(ipu);
 out_failed_irq:
 	clk_disable_unprepare(ipu->clk);
 failed_clk_get:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 6/8] ARM i.MX5: Add System Reset Controller (SRC) support for i.MX51 and i.MX53
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

The SRC in i.MX51 and i.MX53 is similar to the one in i.MX6q minus
the IPU2 reset line and multi core CPU reset/enable bits.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes since v2:
 - Rebased onto next-20120219
---
 arch/arm/boot/dts/imx6qdl.dtsi |    2 +-
 arch/arm/mach-imx/Kconfig      |    2 ++
 arch/arm/mach-imx/mm-imx5.c    |    2 ++
 arch/arm/mach-imx/src.c        |    4 +++-
 4 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 3e21e92..fb71499 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -513,7 +513,7 @@
 			};
 
 			src: src@020d8000 {
-				compatible = "fsl,imx6q-src";
+				compatible = "fsl,imx6q-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 0x04 0 96 0x04>;
 				#reset-cells = <1>;
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 5052e31..857c1fb 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -166,6 +166,7 @@ config	SOC_IMX51
 	bool
 	select ARCH_MX5
 	select ARCH_MX51
+	select HAVE_IMX_SRC
 	select PINCTRL
 	select PINCTRL_IMX51
 	select SOC_IMX5
@@ -793,6 +794,7 @@ config	SOC_IMX53
 	select ARCH_MX5
 	select ARCH_MX53
 	select HAVE_CAN_FLEXCAN if CAN
+	select HAVE_IMX_SRC
 	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select PINCTRL
 	select PINCTRL_IMX53
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index cf34994..b7c4e70 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -84,6 +84,7 @@ void __init imx51_init_early(void)
 	mxc_set_cpu_type(MXC_CPU_MX51);
 	mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
+	imx_src_init();
 }
 
 void __init imx53_init_early(void)
@@ -91,6 +92,7 @@ void __init imx53_init_early(void)
 	mxc_set_cpu_type(MXC_CPU_MX53);
 	mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR));
+	imx_src_init();
 }
 
 void __init mx51_init_irq(void)
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index 3a39daf..ad77945 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -120,7 +120,9 @@ void __init imx_src_init(void)
 	struct device_node *np;
 	u32 val;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src");
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
+	if (!np)
+		return;
 	src_base = of_iomap(np, 0);
 	WARN_ON(!src_base);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 6/8] ARM i.MX5: Add System Reset Controller (SRC) support for i.MX51 and i.MX53
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

The SRC in i.MX51 and i.MX53 is similar to the one in i.MX6q minus
the IPU2 reset line and multi core CPU reset/enable bits.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
Changes since v2:
 - Rebased onto next-20120219
---
 arch/arm/boot/dts/imx6qdl.dtsi |    2 +-
 arch/arm/mach-imx/Kconfig      |    2 ++
 arch/arm/mach-imx/mm-imx5.c    |    2 ++
 arch/arm/mach-imx/src.c        |    4 +++-
 4 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 3e21e92..fb71499 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -513,7 +513,7 @@
 			};
 
 			src: src at 020d8000 {
-				compatible = "fsl,imx6q-src";
+				compatible = "fsl,imx6q-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 0x04 0 96 0x04>;
 				#reset-cells = <1>;
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 5052e31..857c1fb 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -166,6 +166,7 @@ config	SOC_IMX51
 	bool
 	select ARCH_MX5
 	select ARCH_MX51
+	select HAVE_IMX_SRC
 	select PINCTRL
 	select PINCTRL_IMX51
 	select SOC_IMX5
@@ -793,6 +794,7 @@ config	SOC_IMX53
 	select ARCH_MX5
 	select ARCH_MX53
 	select HAVE_CAN_FLEXCAN if CAN
+	select HAVE_IMX_SRC
 	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select PINCTRL
 	select PINCTRL_IMX53
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index cf34994..b7c4e70 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -84,6 +84,7 @@ void __init imx51_init_early(void)
 	mxc_set_cpu_type(MXC_CPU_MX51);
 	mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
+	imx_src_init();
 }
 
 void __init imx53_init_early(void)
@@ -91,6 +92,7 @@ void __init imx53_init_early(void)
 	mxc_set_cpu_type(MXC_CPU_MX53);
 	mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR));
+	imx_src_init();
 }
 
 void __init mx51_init_irq(void)
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index 3a39daf..ad77945 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -120,7 +120,9 @@ void __init imx_src_init(void)
 	struct device_node *np;
 	u32 val;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src");
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
+	if (!np)
+		return;
 	src_base = of_iomap(np, 0);
 	WARN_ON(!src_base);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 7/8] ARM i.MX5: Add system reset controller (SRC) to i.MX51 and i.MX53 device tree
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Also, link SRC to IPU via phandle.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/imx51.dtsi |    7 +++++++
 arch/arm/boot/dts/imx53.dtsi |    7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index fcf035b..cfe4e92 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -67,6 +67,7 @@
 			compatible = "fsl,imx51-ipu";
 			reg = <0x40000000 0x20000000>;
 			interrupts = <11 10>;
+			resets = <&src 2>;
 		};
 
 		aips@70000000 { /* AIPS1 */
@@ -501,6 +502,12 @@
 				status = "disabled";
 			};
 
+			src: src@73fd0000 {
+				compatible = "fsl,imx51-src";
+				reg = <0x73fd0000 0x4000>;
+				#reset-cells = <1>;
+			};
+
 			clks: ccm@73fd4000{
 				compatible = "fsl,imx51-ccm";
 				reg = <0x73fd4000 0x4000>;
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index d05aa21..9e1348d 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -72,6 +72,7 @@
 			compatible = "fsl,imx53-ipu";
 			reg = <0x18000000 0x080000000>;
 			interrupts = <11 10>;
+			resets = <&src 2>;
 		};
 
 		aips@50000000 { /* AIPS1 */
@@ -558,6 +559,12 @@
 				status = "disabled";
 			};
 
+			src: src@53fd0000 {
+				compatible = "fsl,imx53-src", "fsl,imx51-src";
+				reg = <0x53fd0000 0x4000>;
+				#reset-cells = <1>;
+			};
+
 			clks: ccm@53fd4000{
 				compatible = "fsl,imx53-ccm";
 				reg = <0x53fd4000 0x4000>;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 7/8] ARM i.MX5: Add system reset controller (SRC) to i.MX51 and i.MX53 device tree
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Also, link SRC to IPU via phandle.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
 arch/arm/boot/dts/imx51.dtsi |    7 +++++++
 arch/arm/boot/dts/imx53.dtsi |    7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index fcf035b..cfe4e92 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -67,6 +67,7 @@
 			compatible = "fsl,imx51-ipu";
 			reg = <0x40000000 0x20000000>;
 			interrupts = <11 10>;
+			resets = <&src 2>;
 		};
 
 		aips at 70000000 { /* AIPS1 */
@@ -501,6 +502,12 @@
 				status = "disabled";
 			};
 
+			src: src at 73fd0000 {
+				compatible = "fsl,imx51-src";
+				reg = <0x73fd0000 0x4000>;
+				#reset-cells = <1>;
+			};
+
 			clks: ccm at 73fd4000{
 				compatible = "fsl,imx51-ccm";
 				reg = <0x73fd4000 0x4000>;
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index d05aa21..9e1348d 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -72,6 +72,7 @@
 			compatible = "fsl,imx53-ipu";
 			reg = <0x18000000 0x080000000>;
 			interrupts = <11 10>;
+			resets = <&src 2>;
 		};
 
 		aips at 50000000 { /* AIPS1 */
@@ -558,6 +559,12 @@
 				status = "disabled";
 			};
 
+			src: src at 53fd0000 {
+				compatible = "fsl,imx53-src", "fsl,imx51-src";
+				reg = <0x53fd0000 0x4000>;
+				#reset-cells = <1>;
+			};
+
 			clks: ccm at 53fd4000{
 				compatible = "fsl,imx53-ccm";
 				reg = <0x53fd4000 0x4000>;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 11:35     ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Philipp Zabel,
	Sascha Hauer, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

This driver implements a reset controller device that toggles gpios
connected to reset pins of peripheral ICs. The delay between assertion
and de-assertion of the reset signal can be configured.

Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
Changes since v2:
 - Fill reset_controller_dev.owner field.
 - Renamed "gpios" device tree property to "reset-gpios".
 - Added device tree binding documentation.
---
 .../devicetree/bindings/reset/gpio-reset.txt       |   32 ++++
 drivers/reset/Kconfig                              |   13 ++
 drivers/reset/Makefile                             |    1 +
 drivers/reset/gpio-reset.c                         |  189 ++++++++++++++++++++
 4 files changed, 235 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/gpio-reset.txt
 create mode 100644 drivers/reset/gpio-reset.c

diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
new file mode 100644
index 0000000..9dd8781
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/gpio-reset.txt
@@ -0,0 +1,31 @@
+GPIO reset controller
+=====================
+
+A GPIO reset controller controls a number of GPIOs that are connected
+to reset pins of peripheral ICs.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "gpio-reset"
+- reset-gpios: List of gpios used as reset lines. The gpio specifier for this
+               property depends on the gpio controller that provides the gpio.
+- reset-delays: List of delays in ms. The corresponding gpio reset line is
+                asserted for this duration to reset.
+- #reset-cells: 1, see below
+
+example:
+
+gpio_reset: gpio-reset {
+	compatible = "gpio-reset";
+	reset-gpios = <&gpio5 0 1>; /* active-low */
+	reset-delays = <10>; /* 10 ms */
+	#reset-cells = <1>;
+};
+
+/* Device with nRESET pin connected to GPIO5_0 */
+sii902x@39 {
+	/* ... */
+	resets = <&gpio_reset 0>; /* active-low GPIO5_0, 10 ms reset delay */
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c9d04f7..e728d36 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -11,3 +11,16 @@ menuconfig RESET_CONTROLLER
 	  via GPIOs or SoC-internal reset controller modules.
 
 	  If unsure, say no.
+
+if RESET_CONTROLLER
+
+config RESET_GPIO
+	tristate "GPIO reset controller support"
+	depends on GENERIC_GPIO
+	help
+	  This driver provides support for reset lines that are controlled
+	  directly by GPIOs.
+	  The delay between assertion and de-assertion of the reset signal
+	  can be configured.
+
+endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 1e2d83f..b854f20 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_RESET_GPIO) += gpio-reset.o
diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
new file mode 100644
index 0000000..80a1807
--- /dev/null
+++ b/drivers/reset/gpio-reset.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct gpio_reset {
+	unsigned int gpio;
+	unsigned long flags;
+	unsigned int delay_ms;
+};
+
+struct gpio_reset_data {
+	struct reset_controller_dev rcdev;
+	struct gpio_reset *gpios;
+	int nr_gpios;
+};
+
+static void __gpio_reset_set(struct gpio_reset_data *drvdata,
+		unsigned long gpio_idx, int asserted)
+{
+	int value = asserted;
+
+	if (drvdata->gpios[gpio_idx].flags == GPIOF_OUT_INIT_HIGH)
+		value = !value;
+
+	gpio_set_value(drvdata->gpios[gpio_idx].gpio, value);
+}
+
+static int gpio_reset(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	if (drvdata->gpios[gpio_idx].delay_ms < 0)
+		return -ENOSYS;
+
+	__gpio_reset_set(drvdata, gpio_idx, 1);
+	mdelay(drvdata->gpios[gpio_idx].delay_ms);
+	__gpio_reset_set(drvdata, gpio_idx, 0);
+
+	return 0;
+}
+
+static int gpio_reset_assert(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	__gpio_reset_set(drvdata, gpio_idx, 1);
+
+	return 0;
+}
+
+static int gpio_reset_deassert(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	__gpio_reset_set(drvdata, gpio_idx, 0);
+
+	return 0;
+}
+
+static struct reset_control_ops gpio_reset_ops = {
+	.reset = gpio_reset,
+	.assert = gpio_reset_assert,
+	.deassert = gpio_reset_deassert,
+};
+
+static int gpio_reset_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct gpio_reset_data *drvdata;
+	enum of_gpio_flags flags;
+	u32 *delays = NULL;
+	int ret;
+	int i;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (drvdata == NULL)
+		return -ENOMEM;
+
+	drvdata->nr_gpios = of_gpio_named_count(np, "reset-gpios");
+	if (drvdata->nr_gpios < 1)
+		return -EINVAL;
+
+	drvdata->gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio_reset) *
+			drvdata->nr_gpios, GFP_KERNEL);
+	if (drvdata->gpios == NULL)
+		return -ENOMEM;
+
+	if (of_find_property(np, "reset-delays", NULL)) {
+		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
+				drvdata->nr_gpios, GFP_KERNEL);
+		if (delays == NULL)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(np, "reset-delays", delays,
+				drvdata->nr_gpios);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < drvdata->nr_gpios; i++) {
+		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
+				"reset-gpios", i, &flags);
+		if (drvdata->gpios[i].gpio < 0) {
+			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);
+			return drvdata->gpios[i].gpio;
+		}
+
+		/*
+		 * The flags are also used to remember whether a given GPIO
+		 * reset is active-low.
+		 */
+		if (flags & OF_GPIO_ACTIVE_LOW)
+			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+		else
+			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
+
+		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
+				drvdata->gpios[i].flags, NULL);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
+					drvdata->gpios[i].gpio, i);
+			return ret;
+		}
+
+		if (delays != NULL)
+			drvdata->gpios[i].delay_ms = delays[i];
+		else
+			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */
+	}
+
+	devm_kfree(&pdev->dev, delays);
+
+	drvdata->rcdev.of_node = np;
+	drvdata->rcdev.owner = THIS_MODULE;
+	drvdata->rcdev.ops = &gpio_reset_ops;
+	reset_controller_register(&drvdata->rcdev);
+
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+}
+
+static int gpio_reset_remove(struct platform_device *pdev)
+{
+	struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);
+
+	reset_controller_unregister(&drvdata->rcdev);
+
+	return 0;
+}
+
+static struct of_device_id gpio_reset_dt_ids[] = {
+	{ .compatible = "gpio-reset" },
+	{ }
+};
+
+static struct platform_driver gpio_reset_driver = {
+	.probe = gpio_reset_probe,
+	.remove = gpio_reset_remove,
+	.driver = {
+		.name = "gpio-reset",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
+	},
+};
+
+module_platform_driver(gpio_reset_driver);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
@ 2013-02-19 11:35     ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-19 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

This driver implements a reset controller device that toggles gpios
connected to reset pins of peripheral ICs. The delay between assertion
and de-assertion of the reset signal can be configured.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
Changes since v2:
 - Fill reset_controller_dev.owner field.
 - Renamed "gpios" device tree property to "reset-gpios".
 - Added device tree binding documentation.
---
 .../devicetree/bindings/reset/gpio-reset.txt       |   32 ++++
 drivers/reset/Kconfig                              |   13 ++
 drivers/reset/Makefile                             |    1 +
 drivers/reset/gpio-reset.c                         |  189 ++++++++++++++++++++
 4 files changed, 235 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/gpio-reset.txt
 create mode 100644 drivers/reset/gpio-reset.c

diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
new file mode 100644
index 0000000..9dd8781
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/gpio-reset.txt
@@ -0,0 +1,31 @@
+GPIO reset controller
+=====================
+
+A GPIO reset controller controls a number of GPIOs that are connected
+to reset pins of peripheral ICs.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "gpio-reset"
+- reset-gpios: List of gpios used as reset lines. The gpio specifier for this
+               property depends on the gpio controller that provides the gpio.
+- reset-delays: List of delays in ms. The corresponding gpio reset line is
+                asserted for this duration to reset.
+- #reset-cells: 1, see below
+
+example:
+
+gpio_reset: gpio-reset {
+	compatible = "gpio-reset";
+	reset-gpios = <&gpio5 0 1>; /* active-low */
+	reset-delays = <10>; /* 10 ms */
+	#reset-cells = <1>;
+};
+
+/* Device with nRESET pin connected to GPIO5_0 */
+sii902x at 39 {
+	/* ... */
+	resets = <&gpio_reset 0>; /* active-low GPIO5_0, 10 ms reset delay */
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c9d04f7..e728d36 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -11,3 +11,16 @@ menuconfig RESET_CONTROLLER
 	  via GPIOs or SoC-internal reset controller modules.
 
 	  If unsure, say no.
+
+if RESET_CONTROLLER
+
+config RESET_GPIO
+	tristate "GPIO reset controller support"
+	depends on GENERIC_GPIO
+	help
+	  This driver provides support for reset lines that are controlled
+	  directly by GPIOs.
+	  The delay between assertion and de-assertion of the reset signal
+	  can be configured.
+
+endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 1e2d83f..b854f20 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_RESET_GPIO) += gpio-reset.o
diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
new file mode 100644
index 0000000..80a1807
--- /dev/null
+++ b/drivers/reset/gpio-reset.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct gpio_reset {
+	unsigned int gpio;
+	unsigned long flags;
+	unsigned int delay_ms;
+};
+
+struct gpio_reset_data {
+	struct reset_controller_dev rcdev;
+	struct gpio_reset *gpios;
+	int nr_gpios;
+};
+
+static void __gpio_reset_set(struct gpio_reset_data *drvdata,
+		unsigned long gpio_idx, int asserted)
+{
+	int value = asserted;
+
+	if (drvdata->gpios[gpio_idx].flags == GPIOF_OUT_INIT_HIGH)
+		value = !value;
+
+	gpio_set_value(drvdata->gpios[gpio_idx].gpio, value);
+}
+
+static int gpio_reset(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	if (drvdata->gpios[gpio_idx].delay_ms < 0)
+		return -ENOSYS;
+
+	__gpio_reset_set(drvdata, gpio_idx, 1);
+	mdelay(drvdata->gpios[gpio_idx].delay_ms);
+	__gpio_reset_set(drvdata, gpio_idx, 0);
+
+	return 0;
+}
+
+static int gpio_reset_assert(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	__gpio_reset_set(drvdata, gpio_idx, 1);
+
+	return 0;
+}
+
+static int gpio_reset_deassert(struct reset_controller_dev *rcdev,
+		unsigned long gpio_idx)
+{
+	struct gpio_reset_data *drvdata = container_of(rcdev,
+			struct gpio_reset_data, rcdev);
+
+	if (gpio_idx >= drvdata->nr_gpios)
+		return -EINVAL;
+
+	__gpio_reset_set(drvdata, gpio_idx, 0);
+
+	return 0;
+}
+
+static struct reset_control_ops gpio_reset_ops = {
+	.reset = gpio_reset,
+	.assert = gpio_reset_assert,
+	.deassert = gpio_reset_deassert,
+};
+
+static int gpio_reset_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct gpio_reset_data *drvdata;
+	enum of_gpio_flags flags;
+	u32 *delays = NULL;
+	int ret;
+	int i;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (drvdata == NULL)
+		return -ENOMEM;
+
+	drvdata->nr_gpios = of_gpio_named_count(np, "reset-gpios");
+	if (drvdata->nr_gpios < 1)
+		return -EINVAL;
+
+	drvdata->gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio_reset) *
+			drvdata->nr_gpios, GFP_KERNEL);
+	if (drvdata->gpios == NULL)
+		return -ENOMEM;
+
+	if (of_find_property(np, "reset-delays", NULL)) {
+		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
+				drvdata->nr_gpios, GFP_KERNEL);
+		if (delays == NULL)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(np, "reset-delays", delays,
+				drvdata->nr_gpios);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < drvdata->nr_gpios; i++) {
+		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
+				"reset-gpios", i, &flags);
+		if (drvdata->gpios[i].gpio < 0) {
+			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);
+			return drvdata->gpios[i].gpio;
+		}
+
+		/*
+		 * The flags are also used to remember whether a given GPIO
+		 * reset is active-low.
+		 */
+		if (flags & OF_GPIO_ACTIVE_LOW)
+			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+		else
+			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
+
+		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
+				drvdata->gpios[i].flags, NULL);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
+					drvdata->gpios[i].gpio, i);
+			return ret;
+		}
+
+		if (delays != NULL)
+			drvdata->gpios[i].delay_ms = delays[i];
+		else
+			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */
+	}
+
+	devm_kfree(&pdev->dev, delays);
+
+	drvdata->rcdev.of_node = np;
+	drvdata->rcdev.owner = THIS_MODULE;
+	drvdata->rcdev.ops = &gpio_reset_ops;
+	reset_controller_register(&drvdata->rcdev);
+
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+}
+
+static int gpio_reset_remove(struct platform_device *pdev)
+{
+	struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);
+
+	reset_controller_unregister(&drvdata->rcdev);
+
+	return 0;
+}
+
+static struct of_device_id gpio_reset_dt_ids[] = {
+	{ .compatible = "gpio-reset" },
+	{ }
+};
+
+static struct platform_driver gpio_reset_driver = {
+	.probe = gpio_reset_probe,
+	.remove = gpio_reset_remove,
+	.driver = {
+		.name = "gpio-reset",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
+	},
+};
+
+module_platform_driver(gpio_reset_driver);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6
  2013-02-19 11:35 ` Philipp Zabel
@ 2013-02-19 21:23     ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:23 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> The system reset controller (SRC) on i.MX51, i.MX53, and i.MX6q controls
> reset lines to the GPU, VPU, IPU, and OpenVG IP modules.
> 
> The following patches add a simple API for devices to request being reset
> by separate reset controller hardware and implements the reset signal
> device tree binding proposed by Stephen Warren. Contrary to Tegra hardware,
> the i.MX SRC contains self-deasserting reset registers, so I've included
> both ops to manually assert/deassert a reset line, as well as a "reset"
> operation that is supposed to assert the reset line and wait for it to
> deassert.

One note here: Even though Tegra HW doesn't have auto-clear reset
hardware, I'd still tend to prefer that most Tegra drivers use a single
"assert then deassert" API to keep knowledge of the reset mechanisms out
of the individual drivers. Our reset driver would manually assert, sleep
a short time, de-assert within the implementation. Still, a few drivers
do need a bit more control (e.g. PCIe and powergating) so having the
other APIs around is useful too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6
@ 2013-02-19 21:23     ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> The system reset controller (SRC) on i.MX51, i.MX53, and i.MX6q controls
> reset lines to the GPU, VPU, IPU, and OpenVG IP modules.
> 
> The following patches add a simple API for devices to request being reset
> by separate reset controller hardware and implements the reset signal
> device tree binding proposed by Stephen Warren. Contrary to Tegra hardware,
> the i.MX SRC contains self-deasserting reset registers, so I've included
> both ops to manually assert/deassert a reset line, as well as a "reset"
> operation that is supposed to assert the reset line and wait for it to
> deassert.

One note here: Even though Tegra HW doesn't have auto-clear reset
hardware, I'd still tend to prefer that most Tegra drivers use a single
"assert then deassert" API to keep knowledge of the reset mechanisms out
of the individual drivers. Our reset driver would manually assert, sleep
a short time, de-assert within the implementation. Still, a few drivers
do need a bit more control (e.g. PCIe and powergating) so having the
other APIs around is useful too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 2/8] reset: Add reset controller API
  2013-02-19 11:35     ` Philipp Zabel
@ 2013-02-19 21:39         ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:39 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> This adds a simple API for devices to request being reset
> by separate reset controller hardware and implements the
> reset signal device tree binding.

I know I apparently already reviewed this before, but I have a couple
small comments to make.

When I first posted my binding proposal for this, someone said it might
make sense to integrate the reset logic into the existing power domains
support. I think that's drivers/base/power/. It might be worth Cc'ing
the maintainers of that code in case they have comments.

> diff --git a/drivers/Makefile b/drivers/Makefile

> +# reset controllers early, since gpu drivers might rely on them to initialize
> +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/

That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
issues?

> diff --git a/drivers/reset/core.c b/drivers/reset/core.c

> +struct reset_control *reset_control_get(struct device *dev, const char *id)
...
> +	rstc->rcdev = rcdev;
> +	rstc->id = args.args[0];

If the length of args < 1, then that will copy garbage data.

This code will probably work fine for now, but in general, you want to
call a function in the reset controller itself to translate from args to
the reset controller ID. This will allow individual reset controllers to
use a strange mapping for IDs, store flags in the DT cells that
configure the reset (e.g. how long it should be asserted), etc. May as
well add that now. You can add a common implementation that most simple
drivers can use, rather like of_gpio_simple_xlate().

> diff --git a/include/linux/reset.h b/include/linux/reset.h

> +struct reset_control *devm_reset_control_get(struct device *dev, const char *id);

You might want an explicit devm_reset_control_put() too. It's unlikely
it'd get much use, but at least some of the other devm_* functions do
have manual put functions available too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
@ 2013-02-19 21:39         ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> This adds a simple API for devices to request being reset
> by separate reset controller hardware and implements the
> reset signal device tree binding.

I know I apparently already reviewed this before, but I have a couple
small comments to make.

When I first posted my binding proposal for this, someone said it might
make sense to integrate the reset logic into the existing power domains
support. I think that's drivers/base/power/. It might be worth Cc'ing
the maintainers of that code in case they have comments.

> diff --git a/drivers/Makefile b/drivers/Makefile

> +# reset controllers early, since gpu drivers might rely on them to initialize
> +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/

That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
issues?

> diff --git a/drivers/reset/core.c b/drivers/reset/core.c

> +struct reset_control *reset_control_get(struct device *dev, const char *id)
...
> +	rstc->rcdev = rcdev;
> +	rstc->id = args.args[0];

If the length of args < 1, then that will copy garbage data.

This code will probably work fine for now, but in general, you want to
call a function in the reset controller itself to translate from args to
the reset controller ID. This will allow individual reset controllers to
use a strange mapping for IDs, store flags in the DT cells that
configure the reset (e.g. how long it should be asserted), etc. May as
well add that now. You can add a common implementation that most simple
drivers can use, rather like of_gpio_simple_xlate().

> diff --git a/include/linux/reset.h b/include/linux/reset.h

> +struct reset_control *devm_reset_control_get(struct device *dev, const char *id);

You might want an explicit devm_reset_control_put() too. It's unlikely
it'd get much use, but at least some of the other devm_* functions do
have manual put functions available too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 3/8] ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC)
  2013-02-19 11:35     ` Philipp Zabel
@ 2013-02-19 21:41         ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:41 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> The SRC has auto-deasserting reset bits that control reset lines to
> the GPU, VPU, IPU, and OpenVG IP modules. This patch adds a reset
> controller that can be controlled by those devices using the
> reset controller API.

> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig

> +static int imx_src_reset(struct reset_controller_dev *rcdev,
> +		unsigned long sw_reset_idx)
...
> +	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
> +		return -EINVAL;

If each reset controller were to implement an "of_xlate" function, that
error-checking could be implemented there instead. Although that would
prevent using a common shared of_xlate implementation, unless you also
add a "max reset ID" field to struct reset_controller_dev.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 3/8] ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC)
@ 2013-02-19 21:41         ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> The SRC has auto-deasserting reset bits that control reset lines to
> the GPU, VPU, IPU, and OpenVG IP modules. This patch adds a reset
> controller that can be controlled by those devices using the
> reset controller API.

> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig

> +static int imx_src_reset(struct reset_controller_dev *rcdev,
> +		unsigned long sw_reset_idx)
...
> +	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
> +		return -EINVAL;

If each reset controller were to implement an "of_xlate" function, that
error-checking could be implemented there instead. Although that would
prevent using a common shared of_xlate implementation, unless you also
add a "max reset ID" field to struct reset_controller_dev.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
  2013-02-19 11:35     ` Philipp Zabel
@ 2013-02-19 21:57         ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:57 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> This driver implements a reset controller device that toggles gpios
> connected to reset pins of peripheral ICs. The delay between assertion
> and de-assertion of the reset signal can be configured.

> diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt

> +Required properties:

> +- reset-delays: List of delays in ms. The corresponding gpio reset line is
> +                asserted for this duration to reset.

mS are quite long. Would it make sense for this property to be uS instead?

> diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c

> +static int gpio_reset_probe(struct platform_device *pdev)

> +	if (of_find_property(np, "reset-delays", NULL)) {
> +		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
> +				drvdata->nr_gpios, GFP_KERNEL);
> +		if (delays == NULL)
> +			return -ENOMEM;

It'd be nice if there were something like of_property_read_u32_index()
so you could read each value one-by-one in the loop later on, rather
than dynamically allocating this temporarily.

> +		ret = of_property_read_u32_array(np, "reset-delays", delays,
> +				drvdata->nr_gpios);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	for (i = 0; i < drvdata->nr_gpios; i++) {
> +		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
> +				"reset-gpios", i, &flags);
> +		if (drvdata->gpios[i].gpio < 0) {
> +			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);

It's not an error if the value is -EPROBE_DEFERRED; you might want to
explicitly check for that case and not print anything?

> +			return drvdata->gpios[i].gpio;
> +		}
> +
> +		/*
> +		 * The flags are also used to remember whether a given GPIO
> +		 * reset is active-low.
> +		 */
> +		if (flags & OF_GPIO_ACTIVE_LOW)
> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
> +		else
> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;

That raises the question: What is the initial reset state expected to
be? Some devices might want to stay in reset until their driver
explicitly removes the reset signal.

We could handle that by adding another (optional) property indicating
the initial reset state of each GPIO; default to initially not-in-reset
unless that property exists and specifies initially-in-reset.

> +		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
> +				drvdata->gpios[i].flags, NULL);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
> +					drvdata->gpios[i].gpio, i);
> +			return ret;
> +		}

Perhaps first loop to look up all the GPIOs and initialize data
structures, then loop to request the GPIOs? That'd prevent lots of HW
programming and de-programming for the GPIOs near the start of the list,
in the case where some later GPIO causes -EPROBE_DEFERRED, and so this
probe() function keeps getting executed over and over.

> +		if (delays != NULL)
> +			drvdata->gpios[i].delay_ms = delays[i];
> +		else
> +			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */

(here is where of_property_read_u32_index() might be handy)

> +static struct platform_driver gpio_reset_driver = {
> +	.probe = gpio_reset_probe,
> +	.remove = gpio_reset_remove,
> +	.driver = {
> +		.name = "gpio-reset",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
> +	},
> +};
> +
> +module_platform_driver(gpio_reset_driver);

You might want to add a few things like MODULE_AUTHOR,
MODULE_DESCRIPTION,  MODULE_LICENSE,
MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids), perhaps MODULE_ALIAS for the
platform device too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
@ 2013-02-19 21:57         ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-19 21:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> This driver implements a reset controller device that toggles gpios
> connected to reset pins of peripheral ICs. The delay between assertion
> and de-assertion of the reset signal can be configured.

> diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt

> +Required properties:

> +- reset-delays: List of delays in ms. The corresponding gpio reset line is
> +                asserted for this duration to reset.

mS are quite long. Would it make sense for this property to be uS instead?

> diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c

> +static int gpio_reset_probe(struct platform_device *pdev)

> +	if (of_find_property(np, "reset-delays", NULL)) {
> +		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
> +				drvdata->nr_gpios, GFP_KERNEL);
> +		if (delays == NULL)
> +			return -ENOMEM;

It'd be nice if there were something like of_property_read_u32_index()
so you could read each value one-by-one in the loop later on, rather
than dynamically allocating this temporarily.

> +		ret = of_property_read_u32_array(np, "reset-delays", delays,
> +				drvdata->nr_gpios);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	for (i = 0; i < drvdata->nr_gpios; i++) {
> +		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
> +				"reset-gpios", i, &flags);
> +		if (drvdata->gpios[i].gpio < 0) {
> +			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);

It's not an error if the value is -EPROBE_DEFERRED; you might want to
explicitly check for that case and not print anything?

> +			return drvdata->gpios[i].gpio;
> +		}
> +
> +		/*
> +		 * The flags are also used to remember whether a given GPIO
> +		 * reset is active-low.
> +		 */
> +		if (flags & OF_GPIO_ACTIVE_LOW)
> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
> +		else
> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;

That raises the question: What is the initial reset state expected to
be? Some devices might want to stay in reset until their driver
explicitly removes the reset signal.

We could handle that by adding another (optional) property indicating
the initial reset state of each GPIO; default to initially not-in-reset
unless that property exists and specifies initially-in-reset.

> +		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
> +				drvdata->gpios[i].flags, NULL);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
> +					drvdata->gpios[i].gpio, i);
> +			return ret;
> +		}

Perhaps first loop to look up all the GPIOs and initialize data
structures, then loop to request the GPIOs? That'd prevent lots of HW
programming and de-programming for the GPIOs near the start of the list,
in the case where some later GPIO causes -EPROBE_DEFERRED, and so this
probe() function keeps getting executed over and over.

> +		if (delays != NULL)
> +			drvdata->gpios[i].delay_ms = delays[i];
> +		else
> +			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */

(here is where of_property_read_u32_index() might be handy)

> +static struct platform_driver gpio_reset_driver = {
> +	.probe = gpio_reset_probe,
> +	.remove = gpio_reset_remove,
> +	.driver = {
> +		.name = "gpio-reset",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
> +	},
> +};
> +
> +module_platform_driver(gpio_reset_driver);

You might want to add a few things like MODULE_AUTHOR,
MODULE_DESCRIPTION,  MODULE_LICENSE,
MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids), perhaps MODULE_ALIAS for the
platform device too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 2/8] reset: Add reset controller API
  2013-02-19 11:35     ` Philipp Zabel
@ 2013-02-20  2:20         ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2013-02-20  2:20 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Feb 19, 2013 at 12:35:26PM +0100, Philipp Zabel wrote:
> This adds a simple API for devices to request being reset
> by separate reset controller hardware and implements the
> reset signal device tree binding.
> 
> Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Reviewed-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
@ 2013-02-20  2:20         ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2013-02-20  2:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Feb 19, 2013 at 12:35:26PM +0100, Philipp Zabel wrote:
> This adds a simple API for devices to request being reset
> by separate reset controller hardware and implements the
> reset signal device tree binding.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> Reviewed-by: Stephen Warren <swarren@nvidia.com>

Reviewed-by: Shawn Guo <shawn.guo@linaro.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 2/8] reset: Add reset controller API
  2013-02-19 21:39         ` Stephen Warren
@ 2013-02-20 11:04           ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-20 11:04 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer, kernel,
	Shawn Guo, devicetree-discuss, linux-arm-kernel

Hi,

Am Dienstag, den 19.02.2013, 14:39 -0700 schrieb Stephen Warren:
> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> > This adds a simple API for devices to request being reset
> > by separate reset controller hardware and implements the
> > reset signal device tree binding.
> 
> I know I apparently already reviewed this before, but I have a couple
> small comments to make.

this is my fault. I added the Kconfig comment only after you looked at
the patches. Same for the change in reset_control_get below, which is
change enough to argue I should have dropped the Reviewed-by.

> When I first posted my binding proposal for this, someone said it might
> make sense to integrate the reset logic into the existing power domains
> support. I think that's drivers/base/power/. It might be worth Cc'ing
> the maintainers of that code in case they have comments.

For devices that change their power domain related state during a reset,
some kind of integration could be needed.

> > diff --git a/drivers/Makefile b/drivers/Makefile
> 
> > +# reset controllers early, since gpu drivers might rely on them to initialize
> > +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
>
> That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
> issues?

Even so, isn't it useful to avoid the -EPROBE_DEFERRED loop when we
expect other drivers to depend on resources provided by the reset
controller drivers, but not the other way around?

> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> 
> > +struct reset_control *reset_control_get(struct device *dev, const char *id)
> ...
> > +	rstc->rcdev = rcdev;
> > +	rstc->id = args.args[0];
> 
> If the length of args < 1, then that will copy garbage data.

Will fix.

> This code will probably work fine for now, but in general, you want to
> call a function in the reset controller itself to translate from args to
> the reset controller ID. This will allow individual reset controllers to
> use a strange mapping for IDs, store flags in the DT cells that
> configure the reset (e.g. how long it should be asserted), etc. May as
> well add that now. You can add a common implementation that most simple
> drivers can use, rather like of_gpio_simple_xlate().

I wanted to keep it simple in the first round, but I agree. It might be
helpful to add it from the beginning.

> > diff --git a/include/linux/reset.h b/include/linux/reset.h
> 
> > +struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
> 
> You might want an explicit devm_reset_control_put() too. It's unlikely
> it'd get much use, but at least some of the other devm_* functions do
> have manual put functions available too.

Ok.

thanks
Philipp

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
@ 2013-02-20 11:04           ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-20 11:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Am Dienstag, den 19.02.2013, 14:39 -0700 schrieb Stephen Warren:
> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> > This adds a simple API for devices to request being reset
> > by separate reset controller hardware and implements the
> > reset signal device tree binding.
> 
> I know I apparently already reviewed this before, but I have a couple
> small comments to make.

this is my fault. I added the Kconfig comment only after you looked at
the patches. Same for the change in reset_control_get below, which is
change enough to argue I should have dropped the Reviewed-by.

> When I first posted my binding proposal for this, someone said it might
> make sense to integrate the reset logic into the existing power domains
> support. I think that's drivers/base/power/. It might be worth Cc'ing
> the maintainers of that code in case they have comments.

For devices that change their power domain related state during a reset,
some kind of integration could be needed.

> > diff --git a/drivers/Makefile b/drivers/Makefile
> 
> > +# reset controllers early, since gpu drivers might rely on them to initialize
> > +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
>
> That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
> issues?

Even so, isn't it useful to avoid the -EPROBE_DEFERRED loop when we
expect other drivers to depend on resources provided by the reset
controller drivers, but not the other way around?

> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> 
> > +struct reset_control *reset_control_get(struct device *dev, const char *id)
> ...
> > +	rstc->rcdev = rcdev;
> > +	rstc->id = args.args[0];
> 
> If the length of args < 1, then that will copy garbage data.

Will fix.

> This code will probably work fine for now, but in general, you want to
> call a function in the reset controller itself to translate from args to
> the reset controller ID. This will allow individual reset controllers to
> use a strange mapping for IDs, store flags in the DT cells that
> configure the reset (e.g. how long it should be asserted), etc. May as
> well add that now. You can add a common implementation that most simple
> drivers can use, rather like of_gpio_simple_xlate().

I wanted to keep it simple in the first round, but I agree. It might be
helpful to add it from the beginning.

> > diff --git a/include/linux/reset.h b/include/linux/reset.h
> 
> > +struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
> 
> You might want an explicit devm_reset_control_put() too. It's unlikely
> it'd get much use, but at least some of the other devm_* functions do
> have manual put functions available too.

Ok.

thanks
Philipp

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
  2013-02-19 21:57         ` Stephen Warren
@ 2013-02-20 11:22             ` Philipp Zabel
  -1 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-20 11:22 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Am Dienstag, den 19.02.2013, 14:57 -0700 schrieb Stephen Warren:
> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> > This driver implements a reset controller device that toggles gpios
> > connected to reset pins of peripheral ICs. The delay between assertion
> > and de-assertion of the reset signal can be configured.
> 
> > diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
> 
> > +Required properties:
> 
> > +- reset-delays: List of delays in ms. The corresponding gpio reset line is
> > +                asserted for this duration to reset.
> 
> mS are quite long. Would it make sense for this property to be uS instead?

All GPIO resets that I've seen so far wait for several milliseconds.
But I see no downside here to using microseconds instead.

> > diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
> 
> > +static int gpio_reset_probe(struct platform_device *pdev)
> 
> > +	if (of_find_property(np, "reset-delays", NULL)) {
> > +		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
> > +				drvdata->nr_gpios, GFP_KERNEL);
> > +		if (delays == NULL)
> > +			return -ENOMEM;
> 
> It'd be nice if there were something like of_property_read_u32_index()
> so you could read each value one-by-one in the loop later on, rather
> than dynamically allocating this temporarily.

Yes. Let's defer that to a separate patch.

> > +		ret = of_property_read_u32_array(np, "reset-delays", delays,
> > +				drvdata->nr_gpios);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> > +	for (i = 0; i < drvdata->nr_gpios; i++) {
> > +		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
> > +				"reset-gpios", i, &flags);
> > +		if (drvdata->gpios[i].gpio < 0) {
> > +			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);
> 
> It's not an error if the value is -EPROBE_DEFERRED; you might want to
> explicitly check for that case and not print anything?

Right, I'll change that.

> > +			return drvdata->gpios[i].gpio;
> > +		}
> > +
> > +		/*
> > +		 * The flags are also used to remember whether a given GPIO
> > +		 * reset is active-low.
> > +		 */
> > +		if (flags & OF_GPIO_ACTIVE_LOW)
> > +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
> > +		else
> > +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
> 
> That raises the question: What is the initial reset state expected to
> be? Some devices might want to stay in reset until their driver
> explicitly removes the reset signal.
> 
> We could handle that by adding another (optional) property indicating
> the initial reset state of each GPIO; default to initially not-in-reset
> unless that property exists and specifies initially-in-reset.

As with the time parameter, I wonder if this configuration is something
we want to have in the consumer device tree node, or in the gpio-reset
device node:

	gpio_reset: gpio-reset {
		compatible = "gpio-reset";
		reset-gpios = <&gpio2 15 0>;
		reset-delays = <1000>; /* 1 ms */
		initially-in-reset = <1>;
	}
	some-device {
		resets = <&gpio_reset 0>;
	}
vs.
	gpio_reset: gpio-reset {
		compatible = "gpio-reset";
		reset-gpios = <&gpio2 15 0>;
	}
	some-device {
		resets = <&gpio_reset 0 1000>; /* 1 ms */
		initially-in-reset;
	}

> > +		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
> > +				drvdata->gpios[i].flags, NULL);
> > +		if (ret < 0) {
> > +			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
> > +					drvdata->gpios[i].gpio, i);
> > +			return ret;
> > +		}
> 
> Perhaps first loop to look up all the GPIOs and initialize data
> structures, then loop to request the GPIOs? That'd prevent lots of HW
> programming and de-programming for the GPIOs near the start of the list,
> in the case where some later GPIO causes -EPROBE_DEFERRED, and so this
> probe() function keeps getting executed over and over.
> 
> > +		if (delays != NULL)
> > +			drvdata->gpios[i].delay_ms = delays[i];
> > +		else
> > +			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */
> 
> (here is where of_property_read_u32_index() might be handy)
> 
> > +static struct platform_driver gpio_reset_driver = {
> > +	.probe = gpio_reset_probe,
> > +	.remove = gpio_reset_remove,
> > +	.driver = {
> > +		.name = "gpio-reset",
> > +		.owner = THIS_MODULE,
> > +		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
> > +	},
> > +};
> > +
> > +module_platform_driver(gpio_reset_driver);
> 
> You might want to add a few things like MODULE_AUTHOR,
> MODULE_DESCRIPTION,  MODULE_LICENSE,
> MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids), perhaps MODULE_ALIAS for the
> platform device too.

Ok.

thanks
Philipp

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
@ 2013-02-20 11:22             ` Philipp Zabel
  0 siblings, 0 replies; 36+ messages in thread
From: Philipp Zabel @ 2013-02-20 11:22 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, den 19.02.2013, 14:57 -0700 schrieb Stephen Warren:
> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
> > This driver implements a reset controller device that toggles gpios
> > connected to reset pins of peripheral ICs. The delay between assertion
> > and de-assertion of the reset signal can be configured.
> 
> > diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
> 
> > +Required properties:
> 
> > +- reset-delays: List of delays in ms. The corresponding gpio reset line is
> > +                asserted for this duration to reset.
> 
> mS are quite long. Would it make sense for this property to be uS instead?

All GPIO resets that I've seen so far wait for several milliseconds.
But I see no downside here to using microseconds instead.

> > diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
> 
> > +static int gpio_reset_probe(struct platform_device *pdev)
> 
> > +	if (of_find_property(np, "reset-delays", NULL)) {
> > +		delays = devm_kzalloc(&pdev->dev, sizeof(u32) *
> > +				drvdata->nr_gpios, GFP_KERNEL);
> > +		if (delays == NULL)
> > +			return -ENOMEM;
> 
> It'd be nice if there were something like of_property_read_u32_index()
> so you could read each value one-by-one in the loop later on, rather
> than dynamically allocating this temporarily.

Yes. Let's defer that to a separate patch.

> > +		ret = of_property_read_u32_array(np, "reset-delays", delays,
> > +				drvdata->nr_gpios);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> > +	for (i = 0; i < drvdata->nr_gpios; i++) {
> > +		drvdata->gpios[i].gpio = of_get_named_gpio_flags(np,
> > +				"reset-gpios", i, &flags);
> > +		if (drvdata->gpios[i].gpio < 0) {
> > +			dev_err(&pdev->dev, "invalid gpio for reset %d\n", i);
> 
> It's not an error if the value is -EPROBE_DEFERRED; you might want to
> explicitly check for that case and not print anything?

Right, I'll change that.

> > +			return drvdata->gpios[i].gpio;
> > +		}
> > +
> > +		/*
> > +		 * The flags are also used to remember whether a given GPIO
> > +		 * reset is active-low.
> > +		 */
> > +		if (flags & OF_GPIO_ACTIVE_LOW)
> > +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
> > +		else
> > +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
> 
> That raises the question: What is the initial reset state expected to
> be? Some devices might want to stay in reset until their driver
> explicitly removes the reset signal.
> 
> We could handle that by adding another (optional) property indicating
> the initial reset state of each GPIO; default to initially not-in-reset
> unless that property exists and specifies initially-in-reset.

As with the time parameter, I wonder if this configuration is something
we want to have in the consumer device tree node, or in the gpio-reset
device node:

	gpio_reset: gpio-reset {
		compatible = "gpio-reset";
		reset-gpios = <&gpio2 15 0>;
		reset-delays = <1000>; /* 1 ms */
		initially-in-reset = <1>;
	}
	some-device {
		resets = <&gpio_reset 0>;
	}
vs.
	gpio_reset: gpio-reset {
		compatible = "gpio-reset";
		reset-gpios = <&gpio2 15 0>;
	}
	some-device {
		resets = <&gpio_reset 0 1000>; /* 1 ms */
		initially-in-reset;
	}

> > +		ret = devm_gpio_request_one(&pdev->dev, drvdata->gpios[i].gpio,
> > +				drvdata->gpios[i].flags, NULL);
> > +		if (ret < 0) {
> > +			dev_err(&pdev->dev, "failed to request gpio %d for reset %d\n",
> > +					drvdata->gpios[i].gpio, i);
> > +			return ret;
> > +		}
> 
> Perhaps first loop to look up all the GPIOs and initialize data
> structures, then loop to request the GPIOs? That'd prevent lots of HW
> programming and de-programming for the GPIOs near the start of the list,
> in the case where some later GPIO causes -EPROBE_DEFERRED, and so this
> probe() function keeps getting executed over and over.
> 
> > +		if (delays != NULL)
> > +			drvdata->gpios[i].delay_ms = delays[i];
> > +		else
> > +			drvdata->gpios[i].delay_ms = -1; /* .reset returns -ENOSYS */
> 
> (here is where of_property_read_u32_index() might be handy)
> 
> > +static struct platform_driver gpio_reset_driver = {
> > +	.probe = gpio_reset_probe,
> > +	.remove = gpio_reset_remove,
> > +	.driver = {
> > +		.name = "gpio-reset",
> > +		.owner = THIS_MODULE,
> > +		.of_match_table = of_match_ptr(gpio_reset_dt_ids),
> > +	},
> > +};
> > +
> > +module_platform_driver(gpio_reset_driver);
> 
> You might want to add a few things like MODULE_AUTHOR,
> MODULE_DESCRIPTION,  MODULE_LICENSE,
> MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids), perhaps MODULE_ALIAS for the
> platform device too.

Ok.

thanks
Philipp

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 2/8] reset: Add reset controller API
  2013-02-20 11:04           ` Philipp Zabel
@ 2013-02-20 17:10               ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-20 17:10 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/20/2013 04:04 AM, Philipp Zabel wrote:
> Hi,
> 
> Am Dienstag, den 19.02.2013, 14:39 -0700 schrieb Stephen Warren:
>> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
>>> This adds a simple API for devices to request being reset
>>> by separate reset controller hardware and implements the
>>> reset signal device tree binding.

>>> +# reset controllers early, since gpu drivers might rely on them to initialize
>>> +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
>>
>> That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
>> issues?
> 
> Even so, isn't it useful to avoid the -EPROBE_DEFERRED loop when we
> expect other drivers to depend on resources provided by the reset
> controller drivers, but not the other way around?

If this Makefile ordering is solely to reduce the number of times
-EPROBE_DEFERRED is returned, it's probably fine. I just want to make
sure that the ordering isn't required to ensure correctness.

It's quite possible that in general a reset controller driver depends on
clocks, GPIOs, ... from other nodes though, so I'm not sure quite how
much this will buy us in the general case.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 2/8] reset: Add reset controller API
@ 2013-02-20 17:10               ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-20 17:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/20/2013 04:04 AM, Philipp Zabel wrote:
> Hi,
> 
> Am Dienstag, den 19.02.2013, 14:39 -0700 schrieb Stephen Warren:
>> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
>>> This adds a simple API for devices to request being reset
>>> by separate reset controller hardware and implements the
>>> reset signal device tree binding.

>>> +# reset controllers early, since gpu drivers might rely on them to initialize
>>> +obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
>>
>> That sounds odd now. Shouldn't -EPROBE_DEFERRED sort out any ordering
>> issues?
> 
> Even so, isn't it useful to avoid the -EPROBE_DEFERRED loop when we
> expect other drivers to depend on resources provided by the reset
> controller drivers, but not the other way around?

If this Makefile ordering is solely to reduce the number of times
-EPROBE_DEFERRED is returned, it's probably fine. I just want to make
sure that the ordering isn't required to ensure correctness.

It's quite possible that in general a reset controller driver depends on
clocks, GPIOs, ... from other nodes though, so I'm not sure quite how
much this will buy us in the general case.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
  2013-02-20 11:22             ` Philipp Zabel
@ 2013-02-20 17:14                 ` Stephen Warren
  -1 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-20 17:14 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Marek Vasut, Fabio Estevam, Mike Turquette, Sascha Hauer,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/20/2013 04:22 AM, Philipp Zabel wrote:
> Am Dienstag, den 19.02.2013, 14:57 -0700 schrieb Stephen Warren:
>> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
>>> This driver implements a reset controller device that toggles gpios
>>> connected to reset pins of peripheral ICs. The delay between assertion
>>> and de-assertion of the reset signal can be configured.

>>> +		/*
>>> +		 * The flags are also used to remember whether a given GPIO
>>> +		 * reset is active-low.
>>> +		 */
>>> +		if (flags & OF_GPIO_ACTIVE_LOW)
>>> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
>>> +		else
>>> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
>>
>> That raises the question: What is the initial reset state expected to
>> be? Some devices might want to stay in reset until their driver
>> explicitly removes the reset signal.
>>
>> We could handle that by adding another (optional) property indicating
>> the initial reset state of each GPIO; default to initially not-in-reset
>> unless that property exists and specifies initially-in-reset.
> 
> As with the time parameter, I wonder if this configuration is something
> we want to have in the consumer device tree node, or in the gpio-reset
> device node:
> 
> 	gpio_reset: gpio-reset {
> 		compatible = "gpio-reset";
> 		reset-gpios = <&gpio2 15 0>;
> 		reset-delays = <1000>; /* 1 ms */
> 		initially-in-reset = <1>;
> 	}
> 	some-device {
> 		resets = <&gpio_reset 0>;
> 	}
> vs.
> 	gpio_reset: gpio-reset {
> 		compatible = "gpio-reset";
> 		reset-gpios = <&gpio2 15 0>;
> 	}
> 	some-device {
> 		resets = <&gpio_reset 0 1000>; /* 1 ms */
> 		initially-in-reset;
> 	}

I think that the initially-in-reset state has to be represented in the
gpio-reset node, since that's the only node that the GPIO reset driver
will have access to during its probe(), and you're setting up the GPIOs
as outputs during probe(). You can't rely on the drivers for the client
DT nodes to be probed first and provide the information to the reset
controller driver, since probe ordering is undefined. In fact those
probe()s won't have run first, because those devices depend on resources
from the reset controller driver and hence can't probe before it.

If the initially-in-reset properties are in the client device nodes,
then the GPIO reset driver would need to search all nodes for a resets
property that references the appropriate gpio-reset node, then search
for an initially-in-reset property there too. That all seems quite messy.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins
@ 2013-02-20 17:14                 ` Stephen Warren
  0 siblings, 0 replies; 36+ messages in thread
From: Stephen Warren @ 2013-02-20 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/20/2013 04:22 AM, Philipp Zabel wrote:
> Am Dienstag, den 19.02.2013, 14:57 -0700 schrieb Stephen Warren:
>> On 02/19/2013 04:35 AM, Philipp Zabel wrote:
>>> This driver implements a reset controller device that toggles gpios
>>> connected to reset pins of peripheral ICs. The delay between assertion
>>> and de-assertion of the reset signal can be configured.

>>> +		/*
>>> +		 * The flags are also used to remember whether a given GPIO
>>> +		 * reset is active-low.
>>> +		 */
>>> +		if (flags & OF_GPIO_ACTIVE_LOW)
>>> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
>>> +		else
>>> +			drvdata->gpios[i].flags = GPIOF_OUT_INIT_LOW;
>>
>> That raises the question: What is the initial reset state expected to
>> be? Some devices might want to stay in reset until their driver
>> explicitly removes the reset signal.
>>
>> We could handle that by adding another (optional) property indicating
>> the initial reset state of each GPIO; default to initially not-in-reset
>> unless that property exists and specifies initially-in-reset.
> 
> As with the time parameter, I wonder if this configuration is something
> we want to have in the consumer device tree node, or in the gpio-reset
> device node:
> 
> 	gpio_reset: gpio-reset {
> 		compatible = "gpio-reset";
> 		reset-gpios = <&gpio2 15 0>;
> 		reset-delays = <1000>; /* 1 ms */
> 		initially-in-reset = <1>;
> 	}
> 	some-device {
> 		resets = <&gpio_reset 0>;
> 	}
> vs.
> 	gpio_reset: gpio-reset {
> 		compatible = "gpio-reset";
> 		reset-gpios = <&gpio2 15 0>;
> 	}
> 	some-device {
> 		resets = <&gpio_reset 0 1000>; /* 1 ms */
> 		initially-in-reset;
> 	}

I think that the initially-in-reset state has to be represented in the
gpio-reset node, since that's the only node that the GPIO reset driver
will have access to during its probe(), and you're setting up the GPIOs
as outputs during probe(). You can't rely on the drivers for the client
DT nodes to be probed first and provide the information to the reset
controller driver, since probe ordering is undefined. In fact those
probe()s won't have run first, because those devices depend on resources
from the reset controller driver and hence can't probe before it.

If the initially-in-reset properties are in the client device nodes,
then the GPIO reset driver would need to search all nodes for a resets
property that references the appropriate gpio-reset node, then search
for an initially-in-reset property there too. That all seems quite messy.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2013-02-20 17:14 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-19 11:35 [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6 Philipp Zabel
2013-02-19 11:35 ` Philipp Zabel
     [not found] ` <1361273732-23357-1-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-02-19 11:35   ` [PATCH v3 1/8] dt: describe base reset signal binding Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
2013-02-19 11:35   ` [PATCH v3 2/8] reset: Add reset controller API Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
     [not found]     ` <1361273732-23357-3-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-02-19 21:39       ` Stephen Warren
2013-02-19 21:39         ` Stephen Warren
2013-02-20 11:04         ` Philipp Zabel
2013-02-20 11:04           ` Philipp Zabel
     [not found]           ` <1361358260.4937.26.camel-/rZezPiN1rtR6QfukMTsflXZhhPuCNm+@public.gmane.org>
2013-02-20 17:10             ` Stephen Warren
2013-02-20 17:10               ` Stephen Warren
2013-02-20  2:20       ` Shawn Guo
2013-02-20  2:20         ` Shawn Guo
2013-02-19 11:35   ` [PATCH v3 3/8] ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC) Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
     [not found]     ` <1361273732-23357-4-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-02-19 21:41       ` Stephen Warren
2013-02-19 21:41         ` Stephen Warren
2013-02-19 11:35   ` [PATCH v3 4/8] ARM i.MX6q: Link system reset controller (SRC) to IPU in DT Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
2013-02-19 11:35   ` [PATCH v3 5/8] staging: drm/imx: Use SRC to reset IPU Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
2013-02-19 11:35   ` [PATCH v3 6/8] ARM i.MX5: Add System Reset Controller (SRC) support for i.MX51 and i.MX53 Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
2013-02-19 11:35   ` [PATCH v3 7/8] ARM i.MX5: Add system reset controller (SRC) to i.MX51 and i.MX53 device tree Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
2013-02-19 11:35   ` [PATCH v3 8/8] reset: Add driver for gpio-controlled reset pins Philipp Zabel
2013-02-19 11:35     ` Philipp Zabel
     [not found]     ` <1361273732-23357-9-git-send-email-p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-02-19 21:57       ` Stephen Warren
2013-02-19 21:57         ` Stephen Warren
     [not found]         ` <5123F541.4020407-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-02-20 11:22           ` Philipp Zabel
2013-02-20 11:22             ` Philipp Zabel
     [not found]             ` <1361359326.4937.38.camel-/rZezPiN1rtR6QfukMTsflXZhhPuCNm+@public.gmane.org>
2013-02-20 17:14               ` Stephen Warren
2013-02-20 17:14                 ` Stephen Warren
2013-02-19 21:23   ` [PATCH v3 0/8] Reset controller API to reset IP modules on i.MX5 and i.MX6 Stephen Warren
2013-02-19 21:23     ` Stephen Warren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.