diff options
Diffstat (limited to 'target/linux/ramips/patches-3.9/0154-reset-Add-reset-controller-API.patch')
-rw-r--r-- | target/linux/ramips/patches-3.9/0154-reset-Add-reset-controller-API.patch | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-3.9/0154-reset-Add-reset-controller-API.patch b/target/linux/ramips/patches-3.9/0154-reset-Add-reset-controller-API.patch new file mode 100644 index 0000000..900f0a2 --- /dev/null +++ b/target/linux/ramips/patches-3.9/0154-reset-Add-reset-controller-API.patch @@ -0,0 +1,554 @@ +From d6cfbdfa001891894efe078a49ad82ac8a932dbb Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 May 2013 15:42:01 +0200 +Subject: [PATCH 154/164] reset: Add reset controller API + +backport from v3.10-rc1 +61fc41317666be400802ac793f47de816ef7bd57 +6034bb22d8387708075c083385e5d2e1072a4f33 +4e11f848c65b1c87782cb232a6e3b47a9d4c1f98 + +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> +Reviewed-by: Marek Vasut <marex@denx.de> +Reviewed-by: Pavel Machek <pavel@ucw.cz> +--- + Documentation/devicetree/bindings/reset/reset.txt | 75 ++++++ + drivers/Kconfig | 2 + + drivers/Makefile | 3 + + drivers/reset/Kconfig | 13 + + drivers/reset/Makefile | 1 + + drivers/reset/core.c | 297 +++++++++++++++++++++ + include/linux/reset-controller.h | 51 ++++ + include/linux/reset.h | 17 ++ + 8 files changed, 459 insertions(+) + create mode 100644 Documentation/devicetree/bindings/reset/reset.txt + 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/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. +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 dce39a9..1a64c4c 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -37,6 +37,9 @@ obj-$(CONFIG_XEN) += xen/ + # regulators early, since some subsystems rely on them to initialize + obj-$(CONFIG_REGULATOR) += regulator/ + ++# 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..d1b6089 +--- /dev/null ++++ b/drivers/reset/core.c +@@ -0,0 +1,297 @@ ++/* ++ * Reset Controller framework ++ * ++ * Copyright 2013 Philipp Zabel, Pengutronix ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#include <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; ++ struct device *dev; ++ unsigned int id; ++}; ++ ++/** ++ * of_reset_simple_xlate - translate reset_spec to the reset line number ++ * @rcdev: a pointer to the reset controller device ++ * @reset_spec: reset line specifier as found in the device tree ++ * @flags: a flags pointer to fill in (optional) ++ * ++ * This simple translation function should be used for reset controllers ++ * with 1:1 mapping, where reset lines can be indexed by number without gaps. ++ */ ++int of_reset_simple_xlate(struct reset_controller_dev *rcdev, ++ const struct of_phandle_args *reset_spec) ++{ ++ if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) ++ return -EINVAL; ++ ++ if (reset_spec->args[0] >= rcdev->nr_resets) ++ return -EINVAL; ++ ++ return reset_spec->args[0]; ++} ++EXPORT_SYMBOL_GPL(of_reset_simple_xlate); ++ ++/** ++ * 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) ++{ ++ if (!rcdev->of_xlate) { ++ rcdev->of_reset_n_cells = 1; ++ rcdev->of_xlate = of_reset_simple_xlate; ++ } ++ ++ 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 rstc_id; ++ 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; ++ } ++ } ++ of_node_put(args.np); ++ ++ if (!rcdev) { ++ mutex_unlock(&reset_controller_list_mutex); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ rstc_id = rcdev->of_xlate(rcdev, &args); ++ if (rstc_id < 0) { ++ mutex_unlock(&reset_controller_list_mutex); ++ return ERR_PTR(rstc_id); ++ } ++ ++ try_module_get(rcdev->owner); ++ mutex_unlock(&reset_controller_list_mutex); ++ ++ rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); ++ if (!rstc) { ++ module_put(rcdev->owner); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ rstc->dev = dev; ++ rstc->rcdev = rcdev; ++ rstc->id = rstc_id; ++ ++ 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); ++ ++static int devm_reset_control_match(struct device *dev, void *res, void *data) ++{ ++ struct reset_control **rstc = res; ++ if (WARN_ON(!rstc || !*rstc)) ++ return 0; ++ return *rstc == data; ++} ++ ++/** ++ * devm_reset_control_put - resource managed reset_control_put() ++ * @rstc: reset controller to free ++ * ++ * Deallocate a reset control allocated withd devm_reset_control_get(). ++ * This function will not need to be called normally, as devres will take ++ * care of freeing the resource. ++ */ ++void devm_reset_control_put(struct reset_control *rstc) ++{ ++ int ret; ++ ++ ret = devres_release(rstc->dev, devm_reset_control_release, ++ devm_reset_control_match, rstc); ++ if (ret) ++ WARN_ON(ret); ++} ++EXPORT_SYMBOL_GPL(devm_reset_control_put); ++ ++/** ++ * 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..2f61311 +--- /dev/null ++++ b/include/linux/reset-controller.h +@@ -0,0 +1,51 @@ ++#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 ++ * @of_reset_n_cells: number of cells in reset line specifiers ++ * @of_xlate: translation function to translate from specifier as found in the ++ * device tree to id as given to the reset control ops ++ * @nr_resets: number of reset controls in this reset controller device ++ */ ++struct reset_controller_dev { ++ struct reset_control_ops *ops; ++ struct module *owner; ++ struct list_head list; ++ struct device_node *of_node; ++ int of_reset_n_cells; ++ int (*of_xlate)(struct reset_controller_dev *rcdev, ++ const struct of_phandle_args *reset_spec); ++ unsigned int nr_resets; ++}; ++ ++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 + |