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