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