uboot/drivers/reset/reset-ti-sci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Texas Instruments System Control Interface (TI SCI) reset driver
   4 *
   5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
   6 *      Andreas Dannenberg <dannenberg@ti.com>
   7 *
   8 * Loosely based on Linux kernel reset-ti-sci.c...
   9 */
  10
  11#include <common.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <log.h>
  15#include <malloc.h>
  16#include <reset-uclass.h>
  17#include <dm/device_compat.h>
  18#include <linux/err.h>
  19#include <linux/soc/ti/ti_sci_protocol.h>
  20
  21/**
  22 * struct ti_sci_reset_data - reset controller information structure
  23 * @sci: TI SCI handle used for communication with system controller
  24 */
  25struct ti_sci_reset_data {
  26        const struct ti_sci_handle *sci;
  27};
  28
  29static int ti_sci_reset_probe(struct udevice *dev)
  30{
  31        struct ti_sci_reset_data *data = dev_get_priv(dev);
  32
  33        debug("%s(dev=%p)\n", __func__, dev);
  34
  35        if (!data)
  36                return -ENOMEM;
  37
  38        /* Store handle for communication with the system controller */
  39        data->sci = ti_sci_get_handle(dev);
  40        if (IS_ERR(data->sci))
  41                return PTR_ERR(data->sci);
  42
  43        return 0;
  44}
  45
  46static int ti_sci_reset_of_xlate(struct reset_ctl *rst,
  47                                 struct ofnode_phandle_args *args)
  48{
  49        debug("%s(rst=%p, args_count=%d)\n", __func__, rst, args->args_count);
  50
  51        if (args->args_count != 2) {
  52                debug("Invalid args_count: %d\n", args->args_count);
  53                return -EINVAL;
  54        }
  55
  56        /*
  57         * On TI SCI-based devices, the reset provider id field is used as a
  58         * device ID, and the data field is used as the associated reset mask.
  59         */
  60        rst->id = args->args[0];
  61        rst->data = args->args[1];
  62
  63        return 0;
  64}
  65
  66static int ti_sci_reset_request(struct reset_ctl *rst)
  67{
  68        debug("%s(rst=%p)\n", __func__, rst);
  69        return 0;
  70}
  71
  72static int ti_sci_reset_free(struct reset_ctl *rst)
  73{
  74        debug("%s(rst=%p)\n", __func__, rst);
  75        return 0;
  76}
  77
  78/**
  79 * ti_sci_reset_set() - program a device's reset
  80 * @rst: Handle to a single reset signal
  81 * @assert: boolean flag to indicate assert or deassert
  82 *
  83 * This is a common internal function used to assert or deassert a device's
  84 * reset using the TI SCI protocol. The device's reset is asserted if the
  85 * @assert argument is true, or deasserted if @assert argument is false.
  86 * The mechanism itself is a read-modify-write procedure, the current device
  87 * reset register is read using a TI SCI device operation, the new value is
  88 * set or un-set using the reset's mask, and the new reset value written by
  89 * using another TI SCI device operation.
  90 *
  91 * Return: 0 for successful request, else a corresponding error value
  92 */
  93static int ti_sci_reset_set(struct reset_ctl *rst, bool assert)
  94{
  95        struct ti_sci_reset_data *data = dev_get_priv(rst->dev);
  96        const struct ti_sci_handle *sci = data->sci;
  97        const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
  98        u32 reset_state;
  99        int ret;
 100
 101        ret = dops->get_device_resets(sci, rst->id, &reset_state);
 102        if (ret) {
 103                dev_err(rst->dev, "%s: get_device_resets failed (%d)\n",
 104                        __func__, ret);
 105                return ret;
 106        }
 107
 108        if (assert)
 109                reset_state |= rst->data;
 110        else
 111                reset_state &= ~rst->data;
 112
 113        ret = dops->set_device_resets(sci, rst->id, reset_state);
 114        if (ret) {
 115                dev_err(rst->dev, "%s: set_device_resets failed (%d)\n",
 116                        __func__, ret);
 117                return ret;
 118        }
 119
 120        return 0;
 121}
 122
 123/**
 124 * ti_sci_reset_assert() - assert device reset
 125 * @rst: Handle to a single reset signal
 126 *
 127 * This function implements the reset driver op to assert a device's reset
 128 * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
 129 * with the corresponding parameters as passed in, but with the @assert
 130 * argument set to true for asserting the reset.
 131 *
 132 * Return: 0 for successful request, else a corresponding error value
 133 */
 134static int ti_sci_reset_assert(struct reset_ctl *rst)
 135{
 136        debug("%s(rst=%p)\n", __func__, rst);
 137        return ti_sci_reset_set(rst, true);
 138}
 139
 140/**
 141 * ti_sci_reset_deassert() - deassert device reset
 142 * @rst: Handle to a single reset signal
 143 *
 144 * This function implements the reset driver op to deassert a device's reset
 145 * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
 146 * with the corresponding parameters as passed in, but with the @assert
 147 * argument set to false for deasserting the reset.
 148 *
 149 * Return: 0 for successful request, else a corresponding error value
 150 */
 151static int ti_sci_reset_deassert(struct reset_ctl *rst)
 152{
 153        debug("%s(rst=%p)\n", __func__, rst);
 154        return ti_sci_reset_set(rst, false);
 155}
 156
 157/**
 158 * ti_sci_reset_status() - check device reset status
 159 * @rst: Handle to a single reset signal
 160 *
 161 * This function implements the reset driver op to return the status of a
 162 * device's reset using the TI SCI protocol. The reset register value is read
 163 * by invoking the TI SCI device operation .get_device_resets(), and the
 164 * status of the specific reset is extracted and returned using this reset's
 165 * reset mask.
 166 *
 167 * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
 168 */
 169static int ti_sci_reset_status(struct reset_ctl *rst)
 170{
 171        struct ti_sci_reset_data *data = dev_get_priv(rst->dev);
 172        const struct ti_sci_handle *sci = data->sci;
 173        const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
 174        u32 reset_state;
 175        int ret;
 176
 177        debug("%s(rst=%p)\n", __func__, rst);
 178
 179        ret = dops->get_device_resets(sci, rst->id, &reset_state);
 180        if (ret) {
 181                dev_err(rst->dev, "%s: get_device_resets failed (%d)\n",
 182                        __func__, ret);
 183                return ret;
 184        }
 185
 186        return reset_state & rst->data;
 187}
 188
 189static const struct udevice_id ti_sci_reset_of_match[] = {
 190        { .compatible = "ti,sci-reset", },
 191        { /* sentinel */ },
 192};
 193
 194static struct reset_ops ti_sci_reset_ops = {
 195        .of_xlate = ti_sci_reset_of_xlate,
 196        .request = ti_sci_reset_request,
 197        .rfree = ti_sci_reset_free,
 198        .rst_assert = ti_sci_reset_assert,
 199        .rst_deassert = ti_sci_reset_deassert,
 200        .rst_status = ti_sci_reset_status,
 201};
 202
 203U_BOOT_DRIVER(ti_sci_reset) = {
 204        .name = "ti-sci-reset",
 205        .id = UCLASS_RESET,
 206        .of_match = ti_sci_reset_of_match,
 207        .probe = ti_sci_reset_probe,
 208        .priv_auto_alloc_size = sizeof(struct ti_sci_reset_data),
 209        .ops = &ti_sci_reset_ops,
 210};
 211