From aa248927d8dbaa35e0fb920f30d0da2164dc7a98 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 26 Apr 2017 09:50:34 +0200 Subject: reset: sti: Use devm_kcalloc() in syscfg_reset_controller_register() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "devm_kcalloc". * Replace the specification of a data structure by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. * Delete the local variable "size" which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Signed-off-by: Philipp Zabel --- drivers/reset/sti/reset-syscfg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/reset') diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c index 9bd57a5eee72..7e0f2aa55ba7 100644 --- a/drivers/reset/sti/reset-syscfg.c +++ b/drivers/reset/sti/reset-syscfg.c @@ -145,16 +145,14 @@ static int syscfg_reset_controller_register(struct device *dev, const struct syscfg_reset_controller_data *data) { struct syscfg_reset_controller *rc; - size_t size; int i, err; rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL); if (!rc) return -ENOMEM; - size = sizeof(struct syscfg_reset_channel) * data->nr_channels; - - rc->channels = devm_kzalloc(dev, size, GFP_KERNEL); + rc->channels = devm_kcalloc(dev, data->nr_channels, + sizeof(*rc->channels), GFP_KERNEL); if (!rc->channels) return -ENOMEM; -- cgit v1.2.3 From dd9bf8634029fb00fb4797e9ccd648e1335119cb Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 23 May 2017 22:00:12 -0500 Subject: reset: ti_syscon: Rename TI_SYSCON_RESET to RESET_TI_SYSCON Rename the current Kconfig name used for the TI SYSCON Reset driver from TI_SYSCON_RESET to RESET_TI_SYSCON to match the convention used for all the reset drivers present at the base reset folder. Signed-off-by: Suman Anna Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 2 +- drivers/reset/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/reset') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index d21c07ccc94e..42d5631c6da0 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -80,7 +80,7 @@ config RESET_SUNXI help This enables the reset driver for Allwinner SoCs. -config TI_SYSCON_RESET +config RESET_TI_SYSCON tristate "TI SYSCON Reset Driver" depends on HAS_IOMEM select MFD_SYSCON diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 02a74db94339..26270e0f8342 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o -obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o +obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o -- cgit v1.2.3 From 2acb037fc42b8ce5ae59a7d5db3c9b35672e3dd7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 24 May 2017 10:19:20 +0200 Subject: reset: Add a Gemini reset controller The Cortina Systems Gemini reset controller is a simple 32bit register with self-deasserting reset lines. It is accessed using regmap over syscon. Acked-by: Philipp Zabel Signed-off-by: Linus Walleij Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 7 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-gemini.c | 110 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 drivers/reset/reset-gemini.c (limited to 'drivers/reset') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 42d5631c6da0..61fabf6ddaec 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -34,6 +34,13 @@ config RESET_BERLIN help This enables the reset controller driver for Marvell Berlin SoCs. +config RESET_GEMINI + bool "Gemini Reset Driver" if COMPILE_TEST + default ARCH_GEMINI + select MFD_SYSCON + help + This enables the reset controller driver for Cortina Systems Gemini. + config RESET_IMX7 bool "i.MX7 Reset Driver" if COMPILE_TEST default SOC_IMX7D diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 26270e0f8342..e422a04f7b85 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o obj-$(CONFIG_RESET_ATH79) += reset-ath79.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o +obj-$(CONFIG_RESET_GEMINI) += reset-gemini.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o diff --git a/drivers/reset/reset-gemini.c b/drivers/reset/reset-gemini.c new file mode 100644 index 000000000000..a2478997c75b --- /dev/null +++ b/drivers/reset/reset-gemini.c @@ -0,0 +1,110 @@ +/* + * Cortina Gemini Reset controller driver + * Copyright (C) 2017 Linus Walleij + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct gemini_reset - gemini reset controller + * @map: regmap to access the containing system controller + * @rcdev: reset controller device + */ +struct gemini_reset { + struct regmap *map; + struct reset_controller_dev rcdev; +}; + +#define GEMINI_GLOBAL_SOFT_RESET 0x0c + +#define to_gemini_reset(p) \ + container_of((p), struct gemini_reset, rcdev) + +/* + * This is a self-deasserting reset controller. + */ +static int gemini_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct gemini_reset *gr = to_gemini_reset(rcdev); + + /* Manual says to always set BIT 30 (CPU1) to 1 */ + return regmap_write(gr->map, + GEMINI_GLOBAL_SOFT_RESET, + BIT(GEMINI_RESET_CPU1) | BIT(id)); +} + +static int gemini_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct gemini_reset *gr = to_gemini_reset(rcdev); + u32 val; + int ret; + + ret = regmap_read(gr->map, GEMINI_GLOBAL_SOFT_RESET, &val); + if (ret) + return ret; + + return !!(val & BIT(id)); +} + +static const struct reset_control_ops gemini_reset_ops = { + .reset = gemini_reset, + .status = gemini_reset_status, +}; + +static int gemini_reset_probe(struct platform_device *pdev) +{ + struct gemini_reset *gr; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret; + + gr = devm_kzalloc(dev, sizeof(*gr), GFP_KERNEL); + if (!gr) + return -ENOMEM; + + gr->map = syscon_node_to_regmap(np); + if (IS_ERR(gr->map)) { + ret = PTR_ERR(gr->map); + dev_err(dev, "unable to get regmap (%d)", ret); + return ret; + } + gr->rcdev.owner = THIS_MODULE; + gr->rcdev.nr_resets = 32; + gr->rcdev.ops = &gemini_reset_ops; + gr->rcdev.of_node = pdev->dev.of_node; + + ret = devm_reset_controller_register(&pdev->dev, &gr->rcdev); + if (ret) + return ret; + + dev_info(dev, "registered Gemini reset controller\n"); + return 0; +} + +static const struct of_device_id gemini_reset_dt_ids[] = { + { .compatible = "cortina,gemini-syscon", }, + { /* sentinel */ }, +}; + +static struct platform_driver gemini_reset_driver = { + .probe = gemini_reset_probe, + .driver = { + .name = "gemini-reset", + .of_match_table = gemini_reset_dt_ids, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(gemini_reset_driver); -- cgit v1.2.3 From d25e4334c2900f15251f16c8ffc5151db800b2aa Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 31 May 2017 17:42:29 +0200 Subject: reset: use kref for reference counting Use kref for reference counting and enjoy the advantages of refcount_t. Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/reset') diff --git a/drivers/reset/core.c b/drivers/reset/core.c index cd739d2fa160..0090784ff410 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ struct reset_control { struct reset_controller_dev *rcdev; struct list_head list; unsigned int id; - unsigned int refcnt; + struct kref refcnt; bool shared; atomic_t deassert_count; atomic_t triggered_count; @@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal( if (WARN_ON(!rstc->shared || !shared)) return ERR_PTR(-EBUSY); - rstc->refcnt++; + kref_get(&rstc->refcnt); return rstc; } } @@ -302,18 +303,18 @@ static struct reset_control *__reset_control_get_internal( rstc->rcdev = rcdev; list_add(&rstc->list, &rcdev->reset_control_head); rstc->id = index; - rstc->refcnt = 1; + kref_init(&rstc->refcnt); rstc->shared = shared; return rstc; } -static void __reset_control_put_internal(struct reset_control *rstc) +static void __reset_control_release(struct kref *kref) { - lockdep_assert_held(&reset_list_mutex); + struct reset_control *rstc = container_of(kref, struct reset_control, + refcnt); - if (--rstc->refcnt) - return; + lockdep_assert_held(&reset_list_mutex); module_put(rstc->rcdev->owner); @@ -321,6 +322,13 @@ static void __reset_control_put_internal(struct reset_control *rstc) kfree(rstc); } +static void __reset_control_put_internal(struct reset_control *rstc) +{ + lockdep_assert_held(&reset_list_mutex); + + kref_put(&rstc->refcnt, __reset_control_release); +} + struct reset_control *__of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional) @@ -400,7 +408,6 @@ 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_OR_NULL(rstc)) -- cgit v1.2.3 From 28df169b9afa121153ef2a3ef4ceae72512cde6d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 24 May 2017 13:09:30 -0500 Subject: reset: Add the TI SCI reset driver Some TI Keystone family of SoCs contain a system controller (like the Power Management Micro Controller (PMMC) on 66AK2G SoCs) that manage the low-level device control (like clocks, resets etc) for the various hardware modules present on the SoC. These device control operations are provided to the host processor OS through a communication protocol called the TI System Control Interface (TI SCI) protocol. This patch adds a reset driver that communicates to the system controller over the TI SCI protocol for performing reset management of various devices present on the SoC. Various reset functionalities are achieved by the means of different TI SCI device operations provided by the TI SCI framework. Signed-off-by: Andrew F. Davis [s-anna@ti.com: documentation changes, revised commit message] Signed-off-by: Suman Anna Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar [p.zabel@pengutronix.de: const struct reset_control_ops] Signed-off-by: Philipp Zabel --- MAINTAINERS | 1 + drivers/reset/Kconfig | 8 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-ti-sci.c | 269 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 279 insertions(+) create mode 100644 drivers/reset/reset-ti-sci.c (limited to 'drivers/reset') diff --git a/MAINTAINERS b/MAINTAINERS index a4c48ec23a11..545ab28f006a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12631,6 +12631,7 @@ F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt F: include/dt-bindings/genpd/k2g.h F: drivers/soc/ti/ti_sci_pm_domains.c F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt +F: drivers/reset/reset-ti-sci.c THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER M: Hans Verkuil diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 61fabf6ddaec..608c071e4bbf 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -87,6 +87,14 @@ config RESET_SUNXI help This enables the reset driver for Allwinner SoCs. +config RESET_TI_SCI + tristate "TI System Control Interface (TI-SCI) reset driver" + depends on TI_SCI_PROTOCOL + help + This enables the reset driver support over TI System Control Interface + available on some new TI's SoCs. If you wish to use reset resources + managed by the TI System Controller, say Y here. Otherwise, say N. + config RESET_TI_SYSCON tristate "TI SYSCON Reset Driver" depends on HAS_IOMEM diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index e422a04f7b85..7081f9da2599 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o +obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c new file mode 100644 index 000000000000..bf68729ab729 --- /dev/null +++ b/drivers/reset/reset-ti-sci.c @@ -0,0 +1,269 @@ +/* + * Texas Instrument's System Control Interface (TI-SCI) reset driver + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * struct ti_sci_reset_control - reset control structure + * @dev_id: SoC-specific device identifier + * @reset_mask: reset mask to use for toggling reset + * @lock: synchronize reset_mask read-modify-writes + */ +struct ti_sci_reset_control { + u32 dev_id; + u32 reset_mask; + struct mutex lock; +}; + +/** + * struct ti_sci_reset_data - reset controller information structure + * @rcdev: reset controller entity + * @dev: reset controller device pointer + * @sci: TI SCI handle used for communication with system controller + * @idr: idr structure for mapping ids to reset control structures + */ +struct ti_sci_reset_data { + struct reset_controller_dev rcdev; + struct device *dev; + const struct ti_sci_handle *sci; + struct idr idr; +}; + +#define to_ti_sci_reset_data(p) \ + container_of((p), struct ti_sci_reset_data, rcdev) + +/** + * ti_sci_reset_set() - program a device's reset + * @rcdev: reset controller entity + * @id: ID of the reset to toggle + * @assert: boolean flag to indicate assert or deassert + * + * This is a common internal function used to assert or deassert a device's + * reset using the TI SCI protocol. The device's reset is asserted if the + * @assert argument is true, or deasserted if @assert argument is false. + * The mechanism itself is a read-modify-write procedure, the current device + * reset register is read using a TI SCI device operation, the new value is + * set or un-set using the reset's mask, and the new reset value written by + * using another TI SCI device operation. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int ti_sci_reset_set(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev); + const struct ti_sci_handle *sci = data->sci; + const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops; + struct ti_sci_reset_control *control; + u32 reset_state; + int ret; + + control = idr_find(&data->idr, id); + if (!control) + return -EINVAL; + + mutex_lock(&control->lock); + + ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state); + if (ret) + goto out; + + if (assert) + reset_state |= control->reset_mask; + else + reset_state &= ~control->reset_mask; + + ret = dev_ops->set_device_resets(sci, control->dev_id, reset_state); +out: + mutex_unlock(&control->lock); + + return ret; +} + +/** + * ti_sci_reset_assert() - assert device reset + * @rcdev: reset controller entity + * @id: ID of the reset to be asserted + * + * This function implements the reset driver op to assert a device's reset + * using the TI SCI protocol. This invokes the function ti_sci_reset_set() + * with the corresponding parameters as passed in, but with the @assert + * argument set to true for asserting the reset. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int ti_sci_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ti_sci_reset_set(rcdev, id, true); +} + +/** + * ti_sci_reset_deassert() - deassert device reset + * @rcdev: reset controller entity + * @id: ID of the reset to be deasserted + * + * This function implements the reset driver op to deassert a device's reset + * using the TI SCI protocol. This invokes the function ti_sci_reset_set() + * with the corresponding parameters as passed in, but with the @assert + * argument set to false for deasserting the reset. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ti_sci_reset_set(rcdev, id, false); +} + +/** + * ti_sci_reset_status() - check device reset status + * @rcdev: reset controller entity + * @id: ID of reset to be checked + * + * This function implements the reset driver op to return the status of a + * device's reset using the TI SCI protocol. The reset register value is read + * by invoking the TI SCI device operation .get_device_resets(), and the + * status of the specific reset is extracted and returned using this reset's + * reset mask. + * + * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted + */ +static int ti_sci_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev); + const struct ti_sci_handle *sci = data->sci; + const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops; + struct ti_sci_reset_control *control; + u32 reset_state; + int ret; + + control = idr_find(&data->idr, id); + if (!control) + return -EINVAL; + + ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state); + if (ret) + return ret; + + return reset_state & control->reset_mask; +} + +static const struct reset_control_ops ti_sci_reset_ops = { + .assert = ti_sci_reset_assert, + .deassert = ti_sci_reset_deassert, + .status = ti_sci_reset_status, +}; + +/** + * ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID + * @rcdev: reset controller entity + * @reset_spec: OF reset argument specifier + * + * This function performs the translation of the reset argument specifier + * values defined in a reset consumer device node. The function allocates a + * reset control structure for that device reset, and will be used by the + * driver for performing any reset functions on that reset. An idr structure + * is allocated and used to map to the reset control structure. This idr + * is used by the driver to do reset lookups. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev); + struct ti_sci_reset_control *control; + + if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) + return -EINVAL; + + control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL); + if (!control) + return -ENOMEM; + + control->dev_id = reset_spec->args[0]; + control->reset_mask = reset_spec->args[1]; + mutex_init(&control->lock); + + return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL); +} + +static const struct of_device_id ti_sci_reset_of_match[] = { + { .compatible = "ti,sci-reset", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match); + +static int ti_sci_reset_probe(struct platform_device *pdev) +{ + struct ti_sci_reset_data *data; + + if (!pdev->dev.of_node) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->sci = devm_ti_sci_get_handle(&pdev->dev); + if (IS_ERR(data->sci)) + return PTR_ERR(data->sci); + + data->rcdev.ops = &ti_sci_reset_ops; + data->rcdev.owner = THIS_MODULE; + data->rcdev.of_node = pdev->dev.of_node; + data->rcdev.of_reset_n_cells = 2; + data->rcdev.of_xlate = ti_sci_reset_of_xlate; + data->dev = &pdev->dev; + idr_init(&data->idr); + + platform_set_drvdata(pdev, data); + + return reset_controller_register(&data->rcdev); +} + +static int ti_sci_reset_remove(struct platform_device *pdev) +{ + struct ti_sci_reset_data *data = platform_get_drvdata(pdev); + + reset_controller_unregister(&data->rcdev); + + idr_destroy(&data->idr); + + return 0; +} + +static struct platform_driver ti_sci_reset_driver = { + .probe = ti_sci_reset_probe, + .remove = ti_sci_reset_remove, + .driver = { + .name = "ti-sci-reset", + .of_match_table = ti_sci_reset_of_match, + }, +}; +module_platform_driver(ti_sci_reset_driver); + +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3