xref: /OK3568_Linux_fs/kernel/drivers/firmware/arm_scmi/base.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * System Control and Management Interface (SCMI) Base Protocol
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2018 ARM Ltd.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #define pr_fmt(fmt) "SCMI Notifications BASE - " 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 #define SCMI_BASE_NUM_SOURCES		1
17*4882a593Smuzhiyun #define SCMI_BASE_MAX_CMD_ERR_COUNT	1024
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun enum scmi_base_protocol_cmd {
20*4882a593Smuzhiyun 	BASE_DISCOVER_VENDOR = 0x3,
21*4882a593Smuzhiyun 	BASE_DISCOVER_SUB_VENDOR = 0x4,
22*4882a593Smuzhiyun 	BASE_DISCOVER_IMPLEMENT_VERSION = 0x5,
23*4882a593Smuzhiyun 	BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
24*4882a593Smuzhiyun 	BASE_DISCOVER_AGENT = 0x7,
25*4882a593Smuzhiyun 	BASE_NOTIFY_ERRORS = 0x8,
26*4882a593Smuzhiyun 	BASE_SET_DEVICE_PERMISSIONS = 0x9,
27*4882a593Smuzhiyun 	BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
28*4882a593Smuzhiyun 	BASE_RESET_AGENT_CONFIGURATION = 0xb,
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun struct scmi_msg_resp_base_attributes {
32*4882a593Smuzhiyun 	u8 num_protocols;
33*4882a593Smuzhiyun 	u8 num_agents;
34*4882a593Smuzhiyun 	__le16 reserved;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct scmi_msg_base_error_notify {
38*4882a593Smuzhiyun 	__le32 event_control;
39*4882a593Smuzhiyun #define BASE_TP_NOTIFY_ALL	BIT(0)
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct scmi_base_error_notify_payld {
43*4882a593Smuzhiyun 	__le32 agent_id;
44*4882a593Smuzhiyun 	__le32 error_status;
45*4882a593Smuzhiyun #define IS_FATAL_ERROR(x)	((x) & BIT(31))
46*4882a593Smuzhiyun #define ERROR_CMD_COUNT(x)	FIELD_GET(GENMASK(9, 0), (x))
47*4882a593Smuzhiyun 	__le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT];
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /**
51*4882a593Smuzhiyun  * scmi_base_attributes_get() - gets the implementation details
52*4882a593Smuzhiyun  *	that are associated with the base protocol.
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  * @ph: SCMI protocol handle
55*4882a593Smuzhiyun  *
56*4882a593Smuzhiyun  * Return: 0 on success, else appropriate SCMI error.
57*4882a593Smuzhiyun  */
scmi_base_attributes_get(const struct scmi_protocol_handle * ph)58*4882a593Smuzhiyun static int scmi_base_attributes_get(const struct scmi_protocol_handle *ph)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	int ret;
61*4882a593Smuzhiyun 	struct scmi_xfer *t;
62*4882a593Smuzhiyun 	struct scmi_msg_resp_base_attributes *attr_info;
63*4882a593Smuzhiyun 	struct scmi_revision_info *rev = ph->get_priv(ph);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
66*4882a593Smuzhiyun 				      0, sizeof(*attr_info), &t);
67*4882a593Smuzhiyun 	if (ret)
68*4882a593Smuzhiyun 		return ret;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	ret = ph->xops->do_xfer(ph, t);
71*4882a593Smuzhiyun 	if (!ret) {
72*4882a593Smuzhiyun 		attr_info = t->rx.buf;
73*4882a593Smuzhiyun 		rev->num_protocols = attr_info->num_protocols;
74*4882a593Smuzhiyun 		rev->num_agents = attr_info->num_agents;
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	return ret;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /**
83*4882a593Smuzhiyun  * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string.
84*4882a593Smuzhiyun  *
85*4882a593Smuzhiyun  * @ph: SCMI protocol handle
86*4882a593Smuzhiyun  * @sub_vendor: specify true if sub-vendor ID is needed
87*4882a593Smuzhiyun  *
88*4882a593Smuzhiyun  * Return: 0 on success, else appropriate SCMI error.
89*4882a593Smuzhiyun  */
90*4882a593Smuzhiyun static int
scmi_base_vendor_id_get(const struct scmi_protocol_handle * ph,bool sub_vendor)91*4882a593Smuzhiyun scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	u8 cmd;
94*4882a593Smuzhiyun 	int ret, size;
95*4882a593Smuzhiyun 	char *vendor_id;
96*4882a593Smuzhiyun 	struct scmi_xfer *t;
97*4882a593Smuzhiyun 	struct scmi_revision_info *rev = ph->get_priv(ph);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	if (sub_vendor) {
101*4882a593Smuzhiyun 		cmd = BASE_DISCOVER_SUB_VENDOR;
102*4882a593Smuzhiyun 		vendor_id = rev->sub_vendor_id;
103*4882a593Smuzhiyun 		size = ARRAY_SIZE(rev->sub_vendor_id);
104*4882a593Smuzhiyun 	} else {
105*4882a593Smuzhiyun 		cmd = BASE_DISCOVER_VENDOR;
106*4882a593Smuzhiyun 		vendor_id = rev->vendor_id;
107*4882a593Smuzhiyun 		size = ARRAY_SIZE(rev->vendor_id);
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, cmd, 0, size, &t);
111*4882a593Smuzhiyun 	if (ret)
112*4882a593Smuzhiyun 		return ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	ret = ph->xops->do_xfer(ph, t);
115*4882a593Smuzhiyun 	if (!ret)
116*4882a593Smuzhiyun 		memcpy(vendor_id, t->rx.buf, size);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	return ret;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /**
124*4882a593Smuzhiyun  * scmi_base_implementation_version_get() - gets a vendor-specific
125*4882a593Smuzhiyun  *	implementation 32-bit version. The format of the version number is
126*4882a593Smuzhiyun  *	vendor-specific
127*4882a593Smuzhiyun  *
128*4882a593Smuzhiyun  * @ph: SCMI protocol handle
129*4882a593Smuzhiyun  *
130*4882a593Smuzhiyun  * Return: 0 on success, else appropriate SCMI error.
131*4882a593Smuzhiyun  */
132*4882a593Smuzhiyun static int
scmi_base_implementation_version_get(const struct scmi_protocol_handle * ph)133*4882a593Smuzhiyun scmi_base_implementation_version_get(const struct scmi_protocol_handle *ph)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	int ret;
136*4882a593Smuzhiyun 	__le32 *impl_ver;
137*4882a593Smuzhiyun 	struct scmi_xfer *t;
138*4882a593Smuzhiyun 	struct scmi_revision_info *rev = ph->get_priv(ph);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_IMPLEMENT_VERSION,
141*4882a593Smuzhiyun 				      0, sizeof(*impl_ver), &t);
142*4882a593Smuzhiyun 	if (ret)
143*4882a593Smuzhiyun 		return ret;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	ret = ph->xops->do_xfer(ph, t);
146*4882a593Smuzhiyun 	if (!ret) {
147*4882a593Smuzhiyun 		impl_ver = t->rx.buf;
148*4882a593Smuzhiyun 		rev->impl_ver = le32_to_cpu(*impl_ver);
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return ret;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /**
157*4882a593Smuzhiyun  * scmi_base_implementation_list_get() - gets the list of protocols it is
158*4882a593Smuzhiyun  *	OSPM is allowed to access
159*4882a593Smuzhiyun  *
160*4882a593Smuzhiyun  * @ph: SCMI protocol handle
161*4882a593Smuzhiyun  * @protocols_imp: pointer to hold the list of protocol identifiers
162*4882a593Smuzhiyun  *
163*4882a593Smuzhiyun  * Return: 0 on success, else appropriate SCMI error.
164*4882a593Smuzhiyun  */
165*4882a593Smuzhiyun static int
scmi_base_implementation_list_get(const struct scmi_protocol_handle * ph,u8 * protocols_imp)166*4882a593Smuzhiyun scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
167*4882a593Smuzhiyun 				  u8 *protocols_imp)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	u8 *list;
170*4882a593Smuzhiyun 	int ret, loop;
171*4882a593Smuzhiyun 	struct scmi_xfer *t;
172*4882a593Smuzhiyun 	__le32 *num_skip, *num_ret;
173*4882a593Smuzhiyun 	u32 tot_num_ret = 0, loop_num_ret;
174*4882a593Smuzhiyun 	struct device *dev = ph->dev;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_LIST_PROTOCOLS,
177*4882a593Smuzhiyun 				      sizeof(*num_skip), 0, &t);
178*4882a593Smuzhiyun 	if (ret)
179*4882a593Smuzhiyun 		return ret;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	num_skip = t->tx.buf;
182*4882a593Smuzhiyun 	num_ret = t->rx.buf;
183*4882a593Smuzhiyun 	list = t->rx.buf + sizeof(*num_ret);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	do {
186*4882a593Smuzhiyun 		/* Set the number of protocols to be skipped/already read */
187*4882a593Smuzhiyun 		*num_skip = cpu_to_le32(tot_num_ret);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		ret = ph->xops->do_xfer(ph, t);
190*4882a593Smuzhiyun 		if (ret)
191*4882a593Smuzhiyun 			break;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 		loop_num_ret = le32_to_cpu(*num_ret);
194*4882a593Smuzhiyun 		if (loop_num_ret > MAX_PROTOCOLS_IMP - tot_num_ret) {
195*4882a593Smuzhiyun 			dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP");
196*4882a593Smuzhiyun 			break;
197*4882a593Smuzhiyun 		}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		for (loop = 0; loop < loop_num_ret; loop++)
200*4882a593Smuzhiyun 			protocols_imp[tot_num_ret + loop] = *(list + loop);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		tot_num_ret += loop_num_ret;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		ph->xops->reset_rx_to_maxsz(ph, t);
205*4882a593Smuzhiyun 	} while (loop_num_ret);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	return ret;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun  * scmi_base_discover_agent_get() - discover the name of an agent
214*4882a593Smuzhiyun  *
215*4882a593Smuzhiyun  * @ph: SCMI protocol handle
216*4882a593Smuzhiyun  * @id: Agent identifier
217*4882a593Smuzhiyun  * @name: Agent identifier ASCII string
218*4882a593Smuzhiyun  *
219*4882a593Smuzhiyun  * An agent id of 0 is reserved to identify the platform itself.
220*4882a593Smuzhiyun  * Generally operating system is represented as "OSPM"
221*4882a593Smuzhiyun  *
222*4882a593Smuzhiyun  * Return: 0 on success, else appropriate SCMI error.
223*4882a593Smuzhiyun  */
scmi_base_discover_agent_get(const struct scmi_protocol_handle * ph,int id,char * name)224*4882a593Smuzhiyun static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
225*4882a593Smuzhiyun 					int id, char *name)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	int ret;
228*4882a593Smuzhiyun 	struct scmi_xfer *t;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT,
231*4882a593Smuzhiyun 				      sizeof(__le32), SCMI_MAX_STR_SIZE, &t);
232*4882a593Smuzhiyun 	if (ret)
233*4882a593Smuzhiyun 		return ret;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	put_unaligned_le32(id, t->tx.buf);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	ret = ph->xops->do_xfer(ph, t);
238*4882a593Smuzhiyun 	if (!ret)
239*4882a593Smuzhiyun 		strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return ret;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
scmi_base_error_notify(const struct scmi_protocol_handle * ph,bool enable)246*4882a593Smuzhiyun static int scmi_base_error_notify(const struct scmi_protocol_handle *ph,
247*4882a593Smuzhiyun 				  bool enable)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	int ret;
250*4882a593Smuzhiyun 	u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
251*4882a593Smuzhiyun 	struct scmi_xfer *t;
252*4882a593Smuzhiyun 	struct scmi_msg_base_error_notify *cfg;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	ret = ph->xops->xfer_get_init(ph, BASE_NOTIFY_ERRORS,
255*4882a593Smuzhiyun 				      sizeof(*cfg), 0, &t);
256*4882a593Smuzhiyun 	if (ret)
257*4882a593Smuzhiyun 		return ret;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	cfg = t->tx.buf;
260*4882a593Smuzhiyun 	cfg->event_control = cpu_to_le32(evt_cntl);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	ret = ph->xops->do_xfer(ph, t);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	ph->xops->xfer_put(ph, t);
265*4882a593Smuzhiyun 	return ret;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
scmi_base_set_notify_enabled(const struct scmi_protocol_handle * ph,u8 evt_id,u32 src_id,bool enable)268*4882a593Smuzhiyun static int scmi_base_set_notify_enabled(const struct scmi_protocol_handle *ph,
269*4882a593Smuzhiyun 					u8 evt_id, u32 src_id, bool enable)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	int ret;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	ret = scmi_base_error_notify(ph, enable);
274*4882a593Smuzhiyun 	if (ret)
275*4882a593Smuzhiyun 		pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	return ret;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
scmi_base_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)280*4882a593Smuzhiyun static void *scmi_base_fill_custom_report(const struct scmi_protocol_handle *ph,
281*4882a593Smuzhiyun 					  u8 evt_id, ktime_t timestamp,
282*4882a593Smuzhiyun 					  const void *payld, size_t payld_sz,
283*4882a593Smuzhiyun 					  void *report, u32 *src_id)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	int i;
286*4882a593Smuzhiyun 	const struct scmi_base_error_notify_payld *p = payld;
287*4882a593Smuzhiyun 	struct scmi_base_error_report *r = report;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/*
290*4882a593Smuzhiyun 	 * BaseError notification payload is variable in size but
291*4882a593Smuzhiyun 	 * up to a maximum length determined by the struct ponted by p.
292*4882a593Smuzhiyun 	 * Instead payld_sz is the effective length of this notification
293*4882a593Smuzhiyun 	 * payload so cannot be greater of the maximum allowed size as
294*4882a593Smuzhiyun 	 * pointed by p.
295*4882a593Smuzhiyun 	 */
296*4882a593Smuzhiyun 	if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz)
297*4882a593Smuzhiyun 		return NULL;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	r->timestamp = timestamp;
300*4882a593Smuzhiyun 	r->agent_id = le32_to_cpu(p->agent_id);
301*4882a593Smuzhiyun 	r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status));
302*4882a593Smuzhiyun 	r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status));
303*4882a593Smuzhiyun 	for (i = 0; i < r->cmd_count; i++)
304*4882a593Smuzhiyun 		r->reports[i] = le64_to_cpu(p->msg_reports[i]);
305*4882a593Smuzhiyun 	*src_id = 0;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	return r;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun static const struct scmi_event base_events[] = {
311*4882a593Smuzhiyun 	{
312*4882a593Smuzhiyun 		.id = SCMI_EVENT_BASE_ERROR_EVENT,
313*4882a593Smuzhiyun 		.max_payld_sz = sizeof(struct scmi_base_error_notify_payld),
314*4882a593Smuzhiyun 		.max_report_sz = sizeof(struct scmi_base_error_report) +
315*4882a593Smuzhiyun 				  SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64),
316*4882a593Smuzhiyun 	},
317*4882a593Smuzhiyun };
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun static const struct scmi_event_ops base_event_ops = {
320*4882a593Smuzhiyun 	.set_notify_enabled = scmi_base_set_notify_enabled,
321*4882a593Smuzhiyun 	.fill_custom_report = scmi_base_fill_custom_report,
322*4882a593Smuzhiyun };
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun static const struct scmi_protocol_events base_protocol_events = {
325*4882a593Smuzhiyun 	.queue_sz = 4 * SCMI_PROTO_QUEUE_SZ,
326*4882a593Smuzhiyun 	.ops = &base_event_ops,
327*4882a593Smuzhiyun 	.evts = base_events,
328*4882a593Smuzhiyun 	.num_events = ARRAY_SIZE(base_events),
329*4882a593Smuzhiyun 	.num_sources = SCMI_BASE_NUM_SOURCES,
330*4882a593Smuzhiyun };
331*4882a593Smuzhiyun 
scmi_base_protocol_init(const struct scmi_protocol_handle * ph)332*4882a593Smuzhiyun static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	int id, ret;
335*4882a593Smuzhiyun 	u8 *prot_imp;
336*4882a593Smuzhiyun 	u32 version;
337*4882a593Smuzhiyun 	char name[SCMI_MAX_STR_SIZE];
338*4882a593Smuzhiyun 	struct device *dev = ph->dev;
339*4882a593Smuzhiyun 	struct scmi_revision_info *rev = scmi_get_revision_area(ph);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	ret = ph->xops->version_get(ph, &version);
342*4882a593Smuzhiyun 	if (ret)
343*4882a593Smuzhiyun 		return ret;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	prot_imp = devm_kcalloc(dev, MAX_PROTOCOLS_IMP, sizeof(u8), GFP_KERNEL);
346*4882a593Smuzhiyun 	if (!prot_imp)
347*4882a593Smuzhiyun 		return -ENOMEM;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	rev->major_ver = PROTOCOL_REV_MAJOR(version),
350*4882a593Smuzhiyun 	rev->minor_ver = PROTOCOL_REV_MINOR(version);
351*4882a593Smuzhiyun 	ph->set_priv(ph, rev);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	scmi_base_attributes_get(ph);
354*4882a593Smuzhiyun 	scmi_base_vendor_id_get(ph, false);
355*4882a593Smuzhiyun 	scmi_base_vendor_id_get(ph, true);
356*4882a593Smuzhiyun 	scmi_base_implementation_version_get(ph);
357*4882a593Smuzhiyun 	scmi_base_implementation_list_get(ph, prot_imp);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	scmi_setup_protocol_implemented(ph, prot_imp);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n",
362*4882a593Smuzhiyun 		 rev->major_ver, rev->minor_ver, rev->vendor_id,
363*4882a593Smuzhiyun 		 rev->sub_vendor_id, rev->impl_ver);
364*4882a593Smuzhiyun 	dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
365*4882a593Smuzhiyun 		rev->num_agents);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	for (id = 0; id < rev->num_agents; id++) {
368*4882a593Smuzhiyun 		scmi_base_discover_agent_get(ph, id, name);
369*4882a593Smuzhiyun 		dev_dbg(dev, "Agent %d: %s\n", id, name);
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return 0;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun static const struct scmi_protocol scmi_base = {
376*4882a593Smuzhiyun 	.id = SCMI_PROTOCOL_BASE,
377*4882a593Smuzhiyun 	.owner = NULL,
378*4882a593Smuzhiyun 	.init_instance = &scmi_base_protocol_init,
379*4882a593Smuzhiyun 	.ops = NULL,
380*4882a593Smuzhiyun 	.events = &base_protocol_events,
381*4882a593Smuzhiyun };
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
384