Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/arm_scmi/reset.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* System Control and Management Interface (SCMI) Reset Protocol
4
*
5
* Copyright (C) 2019-2022 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 "protocols.h"
14
#include "notify.h"
15
16
/* Updated only after ALL the mandatory features for that version are merged */
17
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001
18
19
enum scmi_reset_protocol_cmd {
20
RESET_DOMAIN_ATTRIBUTES = 0x3,
21
RESET = 0x4,
22
RESET_NOTIFY = 0x5,
23
RESET_DOMAIN_NAME_GET = 0x6,
24
};
25
26
#define NUM_RESET_DOMAIN_MASK 0xffff
27
#define RESET_NOTIFY_ENABLE BIT(0)
28
29
struct scmi_msg_resp_reset_domain_attributes {
30
__le32 attributes;
31
#define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31))
32
#define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30))
33
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29))
34
__le32 latency;
35
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
36
};
37
38
struct scmi_msg_reset_domain_reset {
39
__le32 domain_id;
40
__le32 flags;
41
#define AUTONOMOUS_RESET BIT(0)
42
#define EXPLICIT_RESET_ASSERT BIT(1)
43
#define ASYNCHRONOUS_RESET BIT(2)
44
__le32 reset_state;
45
#define ARCH_COLD_RESET 0
46
};
47
48
struct scmi_msg_reset_notify {
49
__le32 id;
50
__le32 event_control;
51
#define RESET_TP_NOTIFY_ALL BIT(0)
52
};
53
54
struct scmi_reset_issued_notify_payld {
55
__le32 agent_id;
56
__le32 domain_id;
57
__le32 reset_state;
58
};
59
60
struct reset_dom_info {
61
bool async_reset;
62
bool reset_notify;
63
u32 latency_us;
64
char name[SCMI_MAX_STR_SIZE];
65
};
66
67
struct scmi_reset_info {
68
u32 version;
69
int num_domains;
70
bool notify_reset_cmd;
71
struct reset_dom_info *dom_info;
72
};
73
74
static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
75
struct scmi_reset_info *pi)
76
{
77
int ret;
78
struct scmi_xfer *t;
79
u32 attr;
80
81
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
82
0, sizeof(attr), &t);
83
if (ret)
84
return ret;
85
86
ret = ph->xops->do_xfer(ph, t);
87
if (!ret) {
88
attr = get_unaligned_le32(t->rx.buf);
89
pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
90
}
91
92
ph->xops->xfer_put(ph, t);
93
94
if (!ret)
95
if (!ph->hops->protocol_msg_check(ph, RESET_NOTIFY, NULL))
96
pi->notify_reset_cmd = true;
97
98
return ret;
99
}
100
101
static int
102
scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
103
struct scmi_reset_info *pinfo,
104
u32 domain, u32 version)
105
{
106
int ret;
107
u32 attributes;
108
struct scmi_xfer *t;
109
struct scmi_msg_resp_reset_domain_attributes *attr;
110
struct reset_dom_info *dom_info = pinfo->dom_info + domain;
111
112
ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
113
sizeof(domain), sizeof(*attr), &t);
114
if (ret)
115
return ret;
116
117
put_unaligned_le32(domain, t->tx.buf);
118
attr = t->rx.buf;
119
120
ret = ph->xops->do_xfer(ph, t);
121
if (!ret) {
122
attributes = le32_to_cpu(attr->attributes);
123
124
dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
125
if (pinfo->notify_reset_cmd)
126
dom_info->reset_notify =
127
SUPPORTS_NOTIFY_RESET(attributes);
128
dom_info->latency_us = le32_to_cpu(attr->latency);
129
if (dom_info->latency_us == U32_MAX)
130
dom_info->latency_us = 0;
131
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
132
}
133
134
ph->xops->xfer_put(ph, t);
135
136
/*
137
* If supported overwrite short name with the extended one;
138
* on error just carry on and use already provided short name.
139
*/
140
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
141
SUPPORTS_EXTENDED_NAMES(attributes))
142
ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
143
NULL, dom_info->name,
144
SCMI_MAX_STR_SIZE);
145
146
return ret;
147
}
148
149
static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
150
{
151
struct scmi_reset_info *pi = ph->get_priv(ph);
152
153
return pi->num_domains;
154
}
155
156
static const char *
157
scmi_reset_name_get(const struct scmi_protocol_handle *ph, u32 domain)
158
{
159
struct scmi_reset_info *pi = ph->get_priv(ph);
160
161
struct reset_dom_info *dom = pi->dom_info + domain;
162
163
return dom->name;
164
}
165
166
static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
167
u32 domain)
168
{
169
struct scmi_reset_info *pi = ph->get_priv(ph);
170
struct reset_dom_info *dom = pi->dom_info + domain;
171
172
return dom->latency_us;
173
}
174
175
static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
176
u32 flags, u32 state)
177
{
178
int ret;
179
struct scmi_xfer *t;
180
struct scmi_msg_reset_domain_reset *dom;
181
struct scmi_reset_info *pi = ph->get_priv(ph);
182
struct reset_dom_info *rdom;
183
184
if (domain >= pi->num_domains)
185
return -EINVAL;
186
187
rdom = pi->dom_info + domain;
188
if (rdom->async_reset && flags & AUTONOMOUS_RESET)
189
flags |= ASYNCHRONOUS_RESET;
190
191
ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
192
if (ret)
193
return ret;
194
195
dom = t->tx.buf;
196
dom->domain_id = cpu_to_le32(domain);
197
dom->flags = cpu_to_le32(flags);
198
dom->reset_state = cpu_to_le32(state);
199
200
if (flags & ASYNCHRONOUS_RESET)
201
ret = ph->xops->do_xfer_with_response(ph, t);
202
else
203
ret = ph->xops->do_xfer(ph, t);
204
205
ph->xops->xfer_put(ph, t);
206
return ret;
207
}
208
209
static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
210
u32 domain)
211
{
212
return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET,
213
ARCH_COLD_RESET);
214
}
215
216
static int
217
scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
218
{
219
return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT,
220
ARCH_COLD_RESET);
221
}
222
223
static int
224
scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
225
{
226
return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
227
}
228
229
static const struct scmi_reset_proto_ops reset_proto_ops = {
230
.num_domains_get = scmi_reset_num_domains_get,
231
.name_get = scmi_reset_name_get,
232
.latency_get = scmi_reset_latency_get,
233
.reset = scmi_reset_domain_reset,
234
.assert = scmi_reset_domain_assert,
235
.deassert = scmi_reset_domain_deassert,
236
};
237
238
static bool scmi_reset_notify_supported(const struct scmi_protocol_handle *ph,
239
u8 evt_id, u32 src_id)
240
{
241
struct reset_dom_info *dom;
242
struct scmi_reset_info *pi = ph->get_priv(ph);
243
244
if (evt_id != SCMI_EVENT_RESET_ISSUED || src_id >= pi->num_domains)
245
return false;
246
247
dom = pi->dom_info + src_id;
248
249
return dom->reset_notify;
250
}
251
252
static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
253
u32 domain_id, bool enable)
254
{
255
int ret;
256
u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0;
257
struct scmi_xfer *t;
258
struct scmi_msg_reset_notify *cfg;
259
260
ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t);
261
if (ret)
262
return ret;
263
264
cfg = t->tx.buf;
265
cfg->id = cpu_to_le32(domain_id);
266
cfg->event_control = cpu_to_le32(evt_cntl);
267
268
ret = ph->xops->do_xfer(ph, t);
269
270
ph->xops->xfer_put(ph, t);
271
return ret;
272
}
273
274
static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph,
275
u8 evt_id, u32 src_id, bool enable)
276
{
277
int ret;
278
279
ret = scmi_reset_notify(ph, src_id, enable);
280
if (ret)
281
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
282
evt_id, src_id, ret);
283
284
return ret;
285
}
286
287
static void *
288
scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph,
289
u8 evt_id, ktime_t timestamp,
290
const void *payld, size_t payld_sz,
291
void *report, u32 *src_id)
292
{
293
const struct scmi_reset_issued_notify_payld *p = payld;
294
struct scmi_reset_issued_report *r = report;
295
296
if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz)
297
return NULL;
298
299
r->timestamp = timestamp;
300
r->agent_id = le32_to_cpu(p->agent_id);
301
r->domain_id = le32_to_cpu(p->domain_id);
302
r->reset_state = le32_to_cpu(p->reset_state);
303
*src_id = r->domain_id;
304
305
return r;
306
}
307
308
static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph)
309
{
310
struct scmi_reset_info *pinfo = ph->get_priv(ph);
311
312
if (!pinfo)
313
return -EINVAL;
314
315
return pinfo->num_domains;
316
}
317
318
static const struct scmi_event reset_events[] = {
319
{
320
.id = SCMI_EVENT_RESET_ISSUED,
321
.max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld),
322
.max_report_sz = sizeof(struct scmi_reset_issued_report),
323
},
324
};
325
326
static const struct scmi_event_ops reset_event_ops = {
327
.is_notify_supported = scmi_reset_notify_supported,
328
.get_num_sources = scmi_reset_get_num_sources,
329
.set_notify_enabled = scmi_reset_set_notify_enabled,
330
.fill_custom_report = scmi_reset_fill_custom_report,
331
};
332
333
static const struct scmi_protocol_events reset_protocol_events = {
334
.queue_sz = SCMI_PROTO_QUEUE_SZ,
335
.ops = &reset_event_ops,
336
.evts = reset_events,
337
.num_events = ARRAY_SIZE(reset_events),
338
};
339
340
static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
341
{
342
int domain, ret;
343
u32 version;
344
struct scmi_reset_info *pinfo;
345
346
ret = ph->xops->version_get(ph, &version);
347
if (ret)
348
return ret;
349
350
dev_dbg(ph->dev, "Reset Version %d.%d\n",
351
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
352
353
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
354
if (!pinfo)
355
return -ENOMEM;
356
357
ret = scmi_reset_attributes_get(ph, pinfo);
358
if (ret)
359
return ret;
360
361
pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
362
sizeof(*pinfo->dom_info), GFP_KERNEL);
363
if (!pinfo->dom_info)
364
return -ENOMEM;
365
366
for (domain = 0; domain < pinfo->num_domains; domain++)
367
scmi_reset_domain_attributes_get(ph, pinfo, domain, version);
368
369
pinfo->version = version;
370
return ph->set_priv(ph, pinfo, version);
371
}
372
373
static const struct scmi_protocol scmi_reset = {
374
.id = SCMI_PROTOCOL_RESET,
375
.owner = THIS_MODULE,
376
.instance_init = &scmi_reset_protocol_init,
377
.ops = &reset_proto_ops,
378
.events = &reset_protocol_events,
379
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
380
};
381
382
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)
383
384