firmware: arm_scmi: Cleanup events registration transient code
[linux-2.6-microblaze.git] / drivers / firmware / arm_scmi / reset.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * System Control and Management Interface (SCMI) Reset Protocol
4  *
5  * Copyright (C) 2019-2021 ARM Ltd.
6  */
7
8 #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt
9
10 #include <linux/scmi_protocol.h>
11
12 #include "common.h"
13 #include "notify.h"
14
15 enum scmi_reset_protocol_cmd {
16         RESET_DOMAIN_ATTRIBUTES = 0x3,
17         RESET = 0x4,
18         RESET_NOTIFY = 0x5,
19 };
20
21 #define NUM_RESET_DOMAIN_MASK   0xffff
22 #define RESET_NOTIFY_ENABLE     BIT(0)
23
24 struct scmi_msg_resp_reset_domain_attributes {
25         __le32 attributes;
26 #define SUPPORTS_ASYNC_RESET(x)         ((x) & BIT(31))
27 #define SUPPORTS_NOTIFY_RESET(x)        ((x) & BIT(30))
28         __le32 latency;
29             u8 name[SCMI_MAX_STR_SIZE];
30 };
31
32 struct scmi_msg_reset_domain_reset {
33         __le32 domain_id;
34         __le32 flags;
35 #define AUTONOMOUS_RESET        BIT(0)
36 #define EXPLICIT_RESET_ASSERT   BIT(1)
37 #define ASYNCHRONOUS_RESET      BIT(2)
38         __le32 reset_state;
39 #define ARCH_COLD_RESET         0
40 };
41
42 struct scmi_msg_reset_notify {
43         __le32 id;
44         __le32 event_control;
45 #define RESET_TP_NOTIFY_ALL     BIT(0)
46 };
47
48 struct scmi_reset_issued_notify_payld {
49         __le32 agent_id;
50         __le32 domain_id;
51         __le32 reset_state;
52 };
53
54 struct reset_dom_info {
55         bool async_reset;
56         bool reset_notify;
57         u32 latency_us;
58         char name[SCMI_MAX_STR_SIZE];
59 };
60
61 struct scmi_reset_info {
62         u32 version;
63         int num_domains;
64         struct reset_dom_info *dom_info;
65 };
66
67 static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
68                                      struct scmi_reset_info *pi)
69 {
70         int ret;
71         struct scmi_xfer *t;
72         u32 attr;
73
74         ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
75                                       0, sizeof(attr), &t);
76         if (ret)
77                 return ret;
78
79         ret = ph->xops->do_xfer(ph, t);
80         if (!ret) {
81                 attr = get_unaligned_le32(t->rx.buf);
82                 pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
83         }
84
85         ph->xops->xfer_put(ph, t);
86         return ret;
87 }
88
89 static int
90 scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
91                                  u32 domain, struct reset_dom_info *dom_info)
92 {
93         int ret;
94         struct scmi_xfer *t;
95         struct scmi_msg_resp_reset_domain_attributes *attr;
96
97         ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
98                                       sizeof(domain), sizeof(*attr), &t);
99         if (ret)
100                 return ret;
101
102         put_unaligned_le32(domain, t->tx.buf);
103         attr = t->rx.buf;
104
105         ret = ph->xops->do_xfer(ph, t);
106         if (!ret) {
107                 u32 attributes = le32_to_cpu(attr->attributes);
108
109                 dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
110                 dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
111                 dom_info->latency_us = le32_to_cpu(attr->latency);
112                 if (dom_info->latency_us == U32_MAX)
113                         dom_info->latency_us = 0;
114                 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
115         }
116
117         ph->xops->xfer_put(ph, t);
118         return ret;
119 }
120
121 static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
122 {
123         struct scmi_reset_info *pi = ph->get_priv(ph);
124
125         return pi->num_domains;
126 }
127
128 static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph,
129                                  u32 domain)
130 {
131         struct scmi_reset_info *pi = ph->get_priv(ph);
132
133         struct reset_dom_info *dom = pi->dom_info + domain;
134
135         return dom->name;
136 }
137
138 static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
139                                   u32 domain)
140 {
141         struct scmi_reset_info *pi = ph->get_priv(ph);
142         struct reset_dom_info *dom = pi->dom_info + domain;
143
144         return dom->latency_us;
145 }
146
147 static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
148                              u32 flags, u32 state)
149 {
150         int ret;
151         struct scmi_xfer *t;
152         struct scmi_msg_reset_domain_reset *dom;
153         struct scmi_reset_info *pi = ph->get_priv(ph);
154         struct reset_dom_info *rdom = pi->dom_info + domain;
155
156         if (rdom->async_reset)
157                 flags |= ASYNCHRONOUS_RESET;
158
159         ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
160         if (ret)
161                 return ret;
162
163         dom = t->tx.buf;
164         dom->domain_id = cpu_to_le32(domain);
165         dom->flags = cpu_to_le32(flags);
166         dom->reset_state = cpu_to_le32(state);
167
168         if (rdom->async_reset)
169                 ret = ph->xops->do_xfer_with_response(ph, t);
170         else
171                 ret = ph->xops->do_xfer(ph, t);
172
173         ph->xops->xfer_put(ph, t);
174         return ret;
175 }
176
177 static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
178                                    u32 domain)
179 {
180         return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET,
181                                  ARCH_COLD_RESET);
182 }
183
184 static int
185 scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
186 {
187         return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT,
188                                  ARCH_COLD_RESET);
189 }
190
191 static int
192 scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
193 {
194         return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
195 }
196
197 static const struct scmi_reset_proto_ops reset_proto_ops = {
198         .num_domains_get = scmi_reset_num_domains_get,
199         .name_get = scmi_reset_name_get,
200         .latency_get = scmi_reset_latency_get,
201         .reset = scmi_reset_domain_reset,
202         .assert = scmi_reset_domain_assert,
203         .deassert = scmi_reset_domain_deassert,
204 };
205
206 static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
207                              u32 domain_id, bool enable)
208 {
209         int ret;
210         u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0;
211         struct scmi_xfer *t;
212         struct scmi_msg_reset_notify *cfg;
213
214         ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t);
215         if (ret)
216                 return ret;
217
218         cfg = t->tx.buf;
219         cfg->id = cpu_to_le32(domain_id);
220         cfg->event_control = cpu_to_le32(evt_cntl);
221
222         ret = ph->xops->do_xfer(ph, t);
223
224         ph->xops->xfer_put(ph, t);
225         return ret;
226 }
227
228 static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph,
229                                          u8 evt_id, u32 src_id, bool enable)
230 {
231         int ret;
232
233         ret = scmi_reset_notify(ph, src_id, enable);
234         if (ret)
235                 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
236                          evt_id, src_id, ret);
237
238         return ret;
239 }
240
241 static void *
242 scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph,
243                               u8 evt_id, ktime_t timestamp,
244                               const void *payld, size_t payld_sz,
245                               void *report, u32 *src_id)
246 {
247         const struct scmi_reset_issued_notify_payld *p = payld;
248         struct scmi_reset_issued_report *r = report;
249
250         if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz)
251                 return NULL;
252
253         r->timestamp = timestamp;
254         r->agent_id = le32_to_cpu(p->agent_id);
255         r->domain_id = le32_to_cpu(p->domain_id);
256         r->reset_state = le32_to_cpu(p->reset_state);
257         *src_id = r->domain_id;
258
259         return r;
260 }
261
262 static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph)
263 {
264         struct scmi_reset_info *pinfo = ph->get_priv(ph);
265
266         if (!pinfo)
267                 return -EINVAL;
268
269         return pinfo->num_domains;
270 }
271
272 static const struct scmi_event reset_events[] = {
273         {
274                 .id = SCMI_EVENT_RESET_ISSUED,
275                 .max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld),
276                 .max_report_sz = sizeof(struct scmi_reset_issued_report),
277         },
278 };
279
280 static const struct scmi_event_ops reset_event_ops = {
281         .get_num_sources = scmi_reset_get_num_sources,
282         .set_notify_enabled = scmi_reset_set_notify_enabled,
283         .fill_custom_report = scmi_reset_fill_custom_report,
284 };
285
286 static const struct scmi_protocol_events reset_protocol_events = {
287         .queue_sz = SCMI_PROTO_QUEUE_SZ,
288         .ops = &reset_event_ops,
289         .evts = reset_events,
290         .num_events = ARRAY_SIZE(reset_events),
291 };
292
293 static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
294 {
295         int domain;
296         u32 version;
297         struct scmi_reset_info *pinfo;
298
299         ph->xops->version_get(ph, &version);
300
301         dev_dbg(ph->dev, "Reset Version %d.%d\n",
302                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
303
304         pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
305         if (!pinfo)
306                 return -ENOMEM;
307
308         scmi_reset_attributes_get(ph, pinfo);
309
310         pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
311                                        sizeof(*pinfo->dom_info), GFP_KERNEL);
312         if (!pinfo->dom_info)
313                 return -ENOMEM;
314
315         for (domain = 0; domain < pinfo->num_domains; domain++) {
316                 struct reset_dom_info *dom = pinfo->dom_info + domain;
317
318                 scmi_reset_domain_attributes_get(ph, domain, dom);
319         }
320
321         pinfo->version = version;
322         return ph->set_priv(ph, pinfo);
323 }
324
325 static const struct scmi_protocol scmi_reset = {
326         .id = SCMI_PROTOCOL_RESET,
327         .instance_init = &scmi_reset_protocol_init,
328         .ops = &reset_proto_ops,
329         .events = &reset_protocol_events,
330 };
331
332 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)