1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) Reset Protocol
5 * Copyright (C) 2019-2022 ARM Ltd.
8 #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt
10 #include <linux/module.h>
11 #include <linux/scmi_protocol.h>
13 #include "protocols.h"
16 /* Updated only after ALL the mandatory features for that version are merged */
17 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001
19 enum scmi_reset_protocol_cmd
{
20 RESET_DOMAIN_ATTRIBUTES
= 0x3,
23 RESET_DOMAIN_NAME_GET
= 0x6,
26 #define NUM_RESET_DOMAIN_MASK 0xffff
27 #define RESET_NOTIFY_ENABLE BIT(0)
29 struct scmi_msg_resp_reset_domain_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))
35 u8 name
[SCMI_SHORT_NAME_MAX_SIZE
];
38 struct scmi_msg_reset_domain_reset
{
41 #define AUTONOMOUS_RESET BIT(0)
42 #define EXPLICIT_RESET_ASSERT BIT(1)
43 #define ASYNCHRONOUS_RESET BIT(2)
45 #define ARCH_COLD_RESET 0
48 struct scmi_msg_reset_notify
{
51 #define RESET_TP_NOTIFY_ALL BIT(0)
54 struct scmi_reset_issued_notify_payld
{
60 struct reset_dom_info
{
64 char name
[SCMI_MAX_STR_SIZE
];
67 struct scmi_reset_info
{
70 bool notify_reset_cmd
;
71 struct reset_dom_info
*dom_info
;
74 static int scmi_reset_attributes_get(const struct scmi_protocol_handle
*ph
,
75 struct scmi_reset_info
*pi
)
81 ret
= ph
->xops
->xfer_get_init(ph
, PROTOCOL_ATTRIBUTES
,
86 ret
= ph
->xops
->do_xfer(ph
, t
);
88 attr
= get_unaligned_le32(t
->rx
.buf
);
89 pi
->num_domains
= attr
& NUM_RESET_DOMAIN_MASK
;
92 ph
->xops
->xfer_put(ph
, t
);
95 if (!ph
->hops
->protocol_msg_check(ph
, RESET_NOTIFY
, NULL
))
96 pi
->notify_reset_cmd
= true;
102 scmi_reset_domain_attributes_get(const struct scmi_protocol_handle
*ph
,
103 struct scmi_reset_info
*pinfo
,
104 u32 domain
, u32 version
)
109 struct scmi_msg_resp_reset_domain_attributes
*attr
;
110 struct reset_dom_info
*dom_info
= pinfo
->dom_info
+ domain
;
112 ret
= ph
->xops
->xfer_get_init(ph
, RESET_DOMAIN_ATTRIBUTES
,
113 sizeof(domain
), sizeof(*attr
), &t
);
117 put_unaligned_le32(domain
, t
->tx
.buf
);
120 ret
= ph
->xops
->do_xfer(ph
, t
);
122 attributes
= le32_to_cpu(attr
->attributes
);
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
);
134 ph
->xops
->xfer_put(ph
, t
);
137 * If supported overwrite short name with the extended one;
138 * on error just carry on and use already provided short name.
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
,
149 static int scmi_reset_num_domains_get(const struct scmi_protocol_handle
*ph
)
151 struct scmi_reset_info
*pi
= ph
->get_priv(ph
);
153 return pi
->num_domains
;
157 scmi_reset_name_get(const struct scmi_protocol_handle
*ph
, u32 domain
)
159 struct scmi_reset_info
*pi
= ph
->get_priv(ph
);
161 struct reset_dom_info
*dom
= pi
->dom_info
+ domain
;
166 static int scmi_reset_latency_get(const struct scmi_protocol_handle
*ph
,
169 struct scmi_reset_info
*pi
= ph
->get_priv(ph
);
170 struct reset_dom_info
*dom
= pi
->dom_info
+ domain
;
172 return dom
->latency_us
;
175 static int scmi_domain_reset(const struct scmi_protocol_handle
*ph
, u32 domain
,
176 u32 flags
, u32 state
)
180 struct scmi_msg_reset_domain_reset
*dom
;
181 struct scmi_reset_info
*pi
= ph
->get_priv(ph
);
182 struct reset_dom_info
*rdom
;
184 if (domain
>= pi
->num_domains
)
187 rdom
= pi
->dom_info
+ domain
;
188 if (rdom
->async_reset
&& flags
& AUTONOMOUS_RESET
)
189 flags
|= ASYNCHRONOUS_RESET
;
191 ret
= ph
->xops
->xfer_get_init(ph
, RESET
, sizeof(*dom
), 0, &t
);
196 dom
->domain_id
= cpu_to_le32(domain
);
197 dom
->flags
= cpu_to_le32(flags
);
198 dom
->reset_state
= cpu_to_le32(state
);
200 if (flags
& ASYNCHRONOUS_RESET
)
201 ret
= ph
->xops
->do_xfer_with_response(ph
, t
);
203 ret
= ph
->xops
->do_xfer(ph
, t
);
205 ph
->xops
->xfer_put(ph
, t
);
209 static int scmi_reset_domain_reset(const struct scmi_protocol_handle
*ph
,
212 return scmi_domain_reset(ph
, domain
, AUTONOMOUS_RESET
,
217 scmi_reset_domain_assert(const struct scmi_protocol_handle
*ph
, u32 domain
)
219 return scmi_domain_reset(ph
, domain
, EXPLICIT_RESET_ASSERT
,
224 scmi_reset_domain_deassert(const struct scmi_protocol_handle
*ph
, u32 domain
)
226 return scmi_domain_reset(ph
, domain
, 0, ARCH_COLD_RESET
);
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
,
238 static bool scmi_reset_notify_supported(const struct scmi_protocol_handle
*ph
,
239 u8 evt_id
, u32 src_id
)
241 struct reset_dom_info
*dom
;
242 struct scmi_reset_info
*pi
= ph
->get_priv(ph
);
244 if (evt_id
!= SCMI_EVENT_RESET_ISSUED
|| src_id
>= pi
->num_domains
)
247 dom
= pi
->dom_info
+ src_id
;
249 return dom
->reset_notify
;
252 static int scmi_reset_notify(const struct scmi_protocol_handle
*ph
,
253 u32 domain_id
, bool enable
)
256 u32 evt_cntl
= enable
? RESET_TP_NOTIFY_ALL
: 0;
258 struct scmi_msg_reset_notify
*cfg
;
260 ret
= ph
->xops
->xfer_get_init(ph
, RESET_NOTIFY
, sizeof(*cfg
), 0, &t
);
265 cfg
->id
= cpu_to_le32(domain_id
);
266 cfg
->event_control
= cpu_to_le32(evt_cntl
);
268 ret
= ph
->xops
->do_xfer(ph
, t
);
270 ph
->xops
->xfer_put(ph
, t
);
274 static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle
*ph
,
275 u8 evt_id
, u32 src_id
, bool enable
)
279 ret
= scmi_reset_notify(ph
, src_id
, enable
);
281 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
282 evt_id
, src_id
, ret
);
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
)
293 const struct scmi_reset_issued_notify_payld
*p
= payld
;
294 struct scmi_reset_issued_report
*r
= report
;
296 if (evt_id
!= SCMI_EVENT_RESET_ISSUED
|| sizeof(*p
) != payld_sz
)
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
;
308 static int scmi_reset_get_num_sources(const struct scmi_protocol_handle
*ph
)
310 struct scmi_reset_info
*pinfo
= ph
->get_priv(ph
);
315 return pinfo
->num_domains
;
318 static const struct scmi_event reset_events
[] = {
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
),
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
,
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
),
340 static int scmi_reset_protocol_init(const struct scmi_protocol_handle
*ph
)
344 struct scmi_reset_info
*pinfo
;
346 ret
= ph
->xops
->version_get(ph
, &version
);
350 dev_dbg(ph
->dev
, "Reset Version %d.%d\n",
351 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
353 pinfo
= devm_kzalloc(ph
->dev
, sizeof(*pinfo
), GFP_KERNEL
);
357 ret
= scmi_reset_attributes_get(ph
, pinfo
);
361 pinfo
->dom_info
= devm_kcalloc(ph
->dev
, pinfo
->num_domains
,
362 sizeof(*pinfo
->dom_info
), GFP_KERNEL
);
363 if (!pinfo
->dom_info
)
366 for (domain
= 0; domain
< pinfo
->num_domains
; domain
++)
367 scmi_reset_domain_attributes_get(ph
, pinfo
, domain
, version
);
369 pinfo
->version
= version
;
370 return ph
->set_priv(ph
, pinfo
, version
);
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
,
382 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset
, scmi_reset
)