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