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