Commit f44a12dc authored by Olof Johansson's avatar Olof Johansson

Merge tag 'reset-for-4.13-2' of git://git.pengutronix.de/git/pza/linux into next/drivers

Reset controller changes for v4.13, part 2

- Add reset manager offsets for Stratix10
- Use kref for reset contol reference counting
- Add new TI SCI reset driver for TI Keystone SoCs

* tag 'reset-for-4.13-2' of git://git.pengutronix.de/git/pza/linux:
  reset: Add the TI SCI reset driver
  dt-bindings: reset: Add TI SCI reset binding
  reset: use kref for reference counting
  dt-bindings: reset: Add reset manager offsets for Stratix10
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 8b4a3587 28df169b
Texas Instruments System Control Interface (TI-SCI) Reset Controller
=====================================================================
Some TI SoCs contain a system controller (like the Power Management Micro
Controller (PMMC) on Keystone 66AK2G SoC) that are responsible for controlling
the state of the various hardware modules present on the SoC. Communication
between the host processor running an OS and the system controller happens
through a protocol called TI System Control Interface (TI-SCI protocol).
For TI SCI details, please refer to the document,
Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
TI-SCI Reset Controller Node
============================
This reset controller node uses the TI SCI protocol to perform the reset
management of various hardware modules present on the SoC. Must be a child
node of the associated TI-SCI system controller node.
Required properties:
--------------------
- compatible : Should be "ti,sci-reset"
- #reset-cells : Should be 2. Please see the reset consumer node below for
usage details.
TI-SCI Reset Consumer Nodes
===========================
Each of the reset consumer nodes should have the following properties,
in addition to their own properties.
Required properties:
--------------------
- resets : A phandle and reset specifier pair, one pair for each reset
signal that affects the device, or that the device manages.
The phandle should point to the TI-SCI reset controller node,
and the reset specifier should have 2 cell-values. The first
cell should contain the device ID. The second cell should
contain the reset mask value used by system controller.
Please refer to the protocol documentation for these values
to be used for different devices,
http://processors.wiki.ti.com/index.php/TISCI#66AK2G02_Data
Please also refer to Documentation/devicetree/bindings/reset/reset.txt for
common reset controller usage by consumers.
Example:
--------
The following example demonstrates both a TI-SCI reset controller node and a
consumer (a DSP device) on the 66AK2G SoC.
pmmc: pmmc {
compatible = "ti,k2g-sci";
k2g_reset: reset-controller {
compatible = "ti,sci-reset";
#reset-cells = <2>;
};
};
dsp0: dsp@10800000 {
...
resets = <&k2g_reset 0x0046 0x1>;
...
};
...@@ -12633,6 +12633,8 @@ F: include/linux/soc/ti/ti_sci_protocol.h ...@@ -12633,6 +12633,8 @@ F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h F: include/dt-bindings/genpd/k2g.h
F: drivers/soc/ti/ti_sci_pm_domains.c 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 THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl> M: Hans Verkuil <hverkuil@xs4all.nl>
......
...@@ -87,6 +87,14 @@ config RESET_SUNXI ...@@ -87,6 +87,14 @@ config RESET_SUNXI
help help
This enables the reset driver for Allwinner SoCs. 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 config RESET_TI_SYSCON
tristate "TI SYSCON Reset Driver" tristate "TI SYSCON Reset Driver"
depends on HAS_IOMEM depends on HAS_IOMEM
......
...@@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o ...@@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.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_TI_SYSCON) += reset-ti-syscon.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/reset.h> #include <linux/reset.h>
...@@ -40,7 +41,7 @@ struct reset_control { ...@@ -40,7 +41,7 @@ struct reset_control {
struct reset_controller_dev *rcdev; struct reset_controller_dev *rcdev;
struct list_head list; struct list_head list;
unsigned int id; unsigned int id;
unsigned int refcnt; struct kref refcnt;
bool shared; bool shared;
atomic_t deassert_count; atomic_t deassert_count;
atomic_t triggered_count; atomic_t triggered_count;
...@@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal( ...@@ -288,7 +289,7 @@ static struct reset_control *__reset_control_get_internal(
if (WARN_ON(!rstc->shared || !shared)) if (WARN_ON(!rstc->shared || !shared))
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
rstc->refcnt++; kref_get(&rstc->refcnt);
return rstc; return rstc;
} }
} }
...@@ -302,18 +303,18 @@ static struct reset_control *__reset_control_get_internal( ...@@ -302,18 +303,18 @@ static struct reset_control *__reset_control_get_internal(
rstc->rcdev = rcdev; rstc->rcdev = rcdev;
list_add(&rstc->list, &rcdev->reset_control_head); list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index; rstc->id = index;
rstc->refcnt = 1; kref_init(&rstc->refcnt);
rstc->shared = shared; rstc->shared = shared;
return rstc; 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) lockdep_assert_held(&reset_list_mutex);
return;
module_put(rstc->rcdev->owner); module_put(rstc->rcdev->owner);
...@@ -321,6 +322,13 @@ static void __reset_control_put_internal(struct reset_control *rstc) ...@@ -321,6 +322,13 @@ static void __reset_control_put_internal(struct reset_control *rstc)
kfree(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, struct reset_control *__of_reset_control_get(struct device_node *node,
const char *id, int index, bool shared, const char *id, int index, bool shared,
bool optional) bool optional)
...@@ -400,7 +408,6 @@ EXPORT_SYMBOL_GPL(__reset_control_get); ...@@ -400,7 +408,6 @@ EXPORT_SYMBOL_GPL(__reset_control_get);
* reset_control_put - free the reset controller * reset_control_put - free the reset controller
* @rstc: reset controller * @rstc: reset controller
*/ */
void reset_control_put(struct reset_control *rstc) void reset_control_put(struct reset_control *rstc)
{ {
if (IS_ERR_OR_NULL(rstc)) if (IS_ERR_OR_NULL(rstc))
......
/*
* Texas Instrument's System Control Interface (TI-SCI) reset driver
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* 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 <linux/idr.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/soc/ti/ti_sci_protocol.h>
/**
* 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 <afd@ti.com>");
MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
MODULE_LICENSE("GPL v2");
/*
* Copyright (C) 2016 Intel Corporation. All rights reserved
* Copyright (C) 2016 Altera Corporation. All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* derived from Steffen Trumtrar's "altr,rst-mgr-a10.h"
*/
#ifndef _DT_BINDINGS_RESET_ALTR_RST_MGR_S10_H
#define _DT_BINDINGS_RESET_ALTR_RST_MGR_S10_H
/* MPUMODRST */
#define CPU0_RESET 0
#define CPU1_RESET 1
#define CPU2_RESET 2
#define CPU3_RESET 3
/* PER0MODRST */
#define EMAC0_RESET 32
#define EMAC1_RESET 33
#define EMAC2_RESET 34
#define USB0_RESET 35
#define USB1_RESET 36
#define NAND_RESET 37
/* 38 is empty */
#define SDMMC_RESET 39
#define EMAC0_OCP_RESET 40
#define EMAC1_OCP_RESET 41
#define EMAC2_OCP_RESET 42
#define USB0_OCP_RESET 43
#define USB1_OCP_RESET 44
#define NAND_OCP_RESET 45
/* 46 is empty */
#define SDMMC_OCP_RESET 47
#define DMA_RESET 48
#define SPIM0_RESET 49
#define SPIM1_RESET 50
#define SPIS0_RESET 51
#define SPIS1_RESET 52
#define DMA_OCP_RESET 53
#define EMAC_PTP_RESET 54
/* 55 is empty*/
#define DMAIF0_RESET 56
#define DMAIF1_RESET 57
#define DMAIF2_RESET 58
#define DMAIF3_RESET 59
#define DMAIF4_RESET 60
#define DMAIF5_RESET 61
#define DMAIF6_RESET 62
#define DMAIF7_RESET 63
/* PER1MODRST */
#define WATCHDOG0_RESET 64
#define WATCHDOG1_RESET 65
#define WATCHDOG2_RESET 66
#define WATCHDOG3_RESET 67
#define L4SYSTIMER0_RESET 68
#define L4SYSTIMER1_RESET 69
#define SPTIMER0_RESET 70
#define SPTIMER1_RESET 71
#define I2C0_RESET 72
#define I2C1_RESET 73
#define I2C2_RESET 74
#define I2C3_RESET 75
#define I2C4_RESET 76
/* 77-79 is empty */
#define UART0_RESET 80
#define UART1_RESET 81
/* 82-87 is empty */
#define GPIO0_RESET 88
#define GPIO1_RESET 89
/* BRGMODRST */
#define SOC2FPGA_RESET 96
#define LWHPS2FPGA_RESET 97
#define FPGA2SOC_RESET 98
#define F2SSDRAM0_RESET 99
#define F2SSDRAM1_RESET 100
#define F2SSDRAM2_RESET 101
#define DDRSCH_RESET 102
/* COLDMODRST */
#define CPUPO0_RESET 160
#define CPUPO1_RESET 161
#define CPUPO2_RESET 162
#define CPUPO3_RESET 163
/* 164-167 is empty */
#define L2_RESET 168
/* DBGMODRST */
#define DBG_RESET 224
#define CSDAP_RESET 225
/* TAPMODRST */
#define TAP_RESET 256
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment