cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

reset-ti-sci.c (8342B)


      1/*
      2 * Texas Instrument's System Control Interface (TI-SCI) reset driver
      3 *
      4 * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
      5 *	Andrew F. Davis <afd@ti.com>
      6 *
      7 * This program is free software; you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License version 2 as
      9 * published by the Free Software Foundation.
     10 *
     11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     12 * kind, whether express or implied; without even the implied warranty
     13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 */
     16
     17#include <linux/idr.h>
     18#include <linux/module.h>
     19#include <linux/mutex.h>
     20#include <linux/of.h>
     21#include <linux/platform_device.h>
     22#include <linux/reset-controller.h>
     23#include <linux/soc/ti/ti_sci_protocol.h>
     24
     25/**
     26 * struct ti_sci_reset_control - reset control structure
     27 * @dev_id: SoC-specific device identifier
     28 * @reset_mask: reset mask to use for toggling reset
     29 * @lock: synchronize reset_mask read-modify-writes
     30 */
     31struct ti_sci_reset_control {
     32	u32 dev_id;
     33	u32 reset_mask;
     34	struct mutex lock;
     35};
     36
     37/**
     38 * struct ti_sci_reset_data - reset controller information structure
     39 * @rcdev: reset controller entity
     40 * @dev: reset controller device pointer
     41 * @sci: TI SCI handle used for communication with system controller
     42 * @idr: idr structure for mapping ids to reset control structures
     43 */
     44struct ti_sci_reset_data {
     45	struct reset_controller_dev rcdev;
     46	struct device *dev;
     47	const struct ti_sci_handle *sci;
     48	struct idr idr;
     49};
     50
     51#define to_ti_sci_reset_data(p)	\
     52	container_of((p), struct ti_sci_reset_data, rcdev)
     53
     54/**
     55 * ti_sci_reset_set() - program a device's reset
     56 * @rcdev: reset controller entity
     57 * @id: ID of the reset to toggle
     58 * @assert: boolean flag to indicate assert or deassert
     59 *
     60 * This is a common internal function used to assert or deassert a device's
     61 * reset using the TI SCI protocol. The device's reset is asserted if the
     62 * @assert argument is true, or deasserted if @assert argument is false.
     63 * The mechanism itself is a read-modify-write procedure, the current device
     64 * reset register is read using a TI SCI device operation, the new value is
     65 * set or un-set using the reset's mask, and the new reset value written by
     66 * using another TI SCI device operation.
     67 *
     68 * Return: 0 for successful request, else a corresponding error value
     69 */
     70static int ti_sci_reset_set(struct reset_controller_dev *rcdev,
     71			    unsigned long id, bool assert)
     72{
     73	struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
     74	const struct ti_sci_handle *sci = data->sci;
     75	const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
     76	struct ti_sci_reset_control *control;
     77	u32 reset_state;
     78	int ret;
     79
     80	control = idr_find(&data->idr, id);
     81	if (!control)
     82		return -EINVAL;
     83
     84	mutex_lock(&control->lock);
     85
     86	ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
     87	if (ret)
     88		goto out;
     89
     90	if (assert)
     91		reset_state |= control->reset_mask;
     92	else
     93		reset_state &= ~control->reset_mask;
     94
     95	ret = dev_ops->set_device_resets(sci, control->dev_id, reset_state);
     96out:
     97	mutex_unlock(&control->lock);
     98
     99	return ret;
    100}
    101
    102/**
    103 * ti_sci_reset_assert() - assert device reset
    104 * @rcdev: reset controller entity
    105 * @id: ID of the reset to be asserted
    106 *
    107 * This function implements the reset driver op to assert a device's reset
    108 * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
    109 * with the corresponding parameters as passed in, but with the @assert
    110 * argument set to true for asserting the reset.
    111 *
    112 * Return: 0 for successful request, else a corresponding error value
    113 */
    114static int ti_sci_reset_assert(struct reset_controller_dev *rcdev,
    115			       unsigned long id)
    116{
    117	return ti_sci_reset_set(rcdev, id, true);
    118}
    119
    120/**
    121 * ti_sci_reset_deassert() - deassert device reset
    122 * @rcdev: reset controller entity
    123 * @id: ID of the reset to be deasserted
    124 *
    125 * This function implements the reset driver op to deassert a device's reset
    126 * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
    127 * with the corresponding parameters as passed in, but with the @assert
    128 * argument set to false for deasserting the reset.
    129 *
    130 * Return: 0 for successful request, else a corresponding error value
    131 */
    132static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev,
    133				 unsigned long id)
    134{
    135	return ti_sci_reset_set(rcdev, id, false);
    136}
    137
    138/**
    139 * ti_sci_reset_status() - check device reset status
    140 * @rcdev: reset controller entity
    141 * @id: ID of reset to be checked
    142 *
    143 * This function implements the reset driver op to return the status of a
    144 * device's reset using the TI SCI protocol. The reset register value is read
    145 * by invoking the TI SCI device operation .get_device_resets(), and the
    146 * status of the specific reset is extracted and returned using this reset's
    147 * reset mask.
    148 *
    149 * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
    150 */
    151static int ti_sci_reset_status(struct reset_controller_dev *rcdev,
    152			       unsigned long id)
    153{
    154	struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
    155	const struct ti_sci_handle *sci = data->sci;
    156	const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
    157	struct ti_sci_reset_control *control;
    158	u32 reset_state;
    159	int ret;
    160
    161	control = idr_find(&data->idr, id);
    162	if (!control)
    163		return -EINVAL;
    164
    165	ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
    166	if (ret)
    167		return ret;
    168
    169	return reset_state & control->reset_mask;
    170}
    171
    172static const struct reset_control_ops ti_sci_reset_ops = {
    173	.assert		= ti_sci_reset_assert,
    174	.deassert	= ti_sci_reset_deassert,
    175	.status		= ti_sci_reset_status,
    176};
    177
    178/**
    179 * ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID
    180 * @rcdev: reset controller entity
    181 * @reset_spec: OF reset argument specifier
    182 *
    183 * This function performs the translation of the reset argument specifier
    184 * values defined in a reset consumer device node. The function allocates a
    185 * reset control structure for that device reset, and will be used by the
    186 * driver for performing any reset functions on that reset. An idr structure
    187 * is allocated and used to map to the reset control structure. This idr
    188 * is used by the driver to do reset lookups.
    189 *
    190 * Return: 0 for successful request, else a corresponding error value
    191 */
    192static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev,
    193				 const struct of_phandle_args *reset_spec)
    194{
    195	struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
    196	struct ti_sci_reset_control *control;
    197
    198	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
    199		return -EINVAL;
    200
    201	control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL);
    202	if (!control)
    203		return -ENOMEM;
    204
    205	control->dev_id = reset_spec->args[0];
    206	control->reset_mask = reset_spec->args[1];
    207	mutex_init(&control->lock);
    208
    209	return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL);
    210}
    211
    212static const struct of_device_id ti_sci_reset_of_match[] = {
    213	{ .compatible = "ti,sci-reset", },
    214	{ /* sentinel */ },
    215};
    216MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match);
    217
    218static int ti_sci_reset_probe(struct platform_device *pdev)
    219{
    220	struct ti_sci_reset_data *data;
    221
    222	if (!pdev->dev.of_node)
    223		return -ENODEV;
    224
    225	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    226	if (!data)
    227		return -ENOMEM;
    228
    229	data->sci = devm_ti_sci_get_handle(&pdev->dev);
    230	if (IS_ERR(data->sci))
    231		return PTR_ERR(data->sci);
    232
    233	data->rcdev.ops = &ti_sci_reset_ops;
    234	data->rcdev.owner = THIS_MODULE;
    235	data->rcdev.of_node = pdev->dev.of_node;
    236	data->rcdev.of_reset_n_cells = 2;
    237	data->rcdev.of_xlate = ti_sci_reset_of_xlate;
    238	data->dev = &pdev->dev;
    239	idr_init(&data->idr);
    240
    241	platform_set_drvdata(pdev, data);
    242
    243	return reset_controller_register(&data->rcdev);
    244}
    245
    246static int ti_sci_reset_remove(struct platform_device *pdev)
    247{
    248	struct ti_sci_reset_data *data = platform_get_drvdata(pdev);
    249
    250	reset_controller_unregister(&data->rcdev);
    251
    252	idr_destroy(&data->idr);
    253
    254	return 0;
    255}
    256
    257static struct platform_driver ti_sci_reset_driver = {
    258	.probe = ti_sci_reset_probe,
    259	.remove = ti_sci_reset_remove,
    260	.driver = {
    261		.name = "ti-sci-reset",
    262		.of_match_table = ti_sci_reset_of_match,
    263	},
    264};
    265module_platform_driver(ti_sci_reset_driver);
    266
    267MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
    268MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
    269MODULE_LICENSE("GPL v2");