xref: /rk3399_ARM-atf/drivers/scmi-msg/base.c (revision b4734308981b651bac64adb90a7b148f252e850a)
1*b4734308SPeng Fan // SPDX-License-Identifier: BSD-3-Clause
2*b4734308SPeng Fan /*
3*b4734308SPeng Fan  * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
4*b4734308SPeng Fan  * Copyright (c) 2019-2020, Linaro Limited
5*b4734308SPeng Fan  */
6*b4734308SPeng Fan #include <assert.h>
7*b4734308SPeng Fan #include <string.h>
8*b4734308SPeng Fan 
9*b4734308SPeng Fan #include <drivers/scmi-msg.h>
10*b4734308SPeng Fan #include <drivers/scmi.h>
11*b4734308SPeng Fan #include <lib/utils.h>
12*b4734308SPeng Fan #include <lib/utils_def.h>
13*b4734308SPeng Fan 
14*b4734308SPeng Fan #include "common.h"
15*b4734308SPeng Fan 
16*b4734308SPeng Fan static bool message_id_is_supported(unsigned int message_id);
17*b4734308SPeng Fan 
18*b4734308SPeng Fan static void report_version(struct scmi_msg *msg)
19*b4734308SPeng Fan {
20*b4734308SPeng Fan 	struct scmi_protocol_version_p2a return_values = {
21*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
22*b4734308SPeng Fan 		.version = SCMI_PROTOCOL_VERSION_BASE,
23*b4734308SPeng Fan 	};
24*b4734308SPeng Fan 
25*b4734308SPeng Fan 	if (msg->in_size != 0U) {
26*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
27*b4734308SPeng Fan 		return;
28*b4734308SPeng Fan 	}
29*b4734308SPeng Fan 
30*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
31*b4734308SPeng Fan }
32*b4734308SPeng Fan 
33*b4734308SPeng Fan static void report_attributes(struct scmi_msg *msg)
34*b4734308SPeng Fan {
35*b4734308SPeng Fan 	size_t protocol_count = plat_scmi_protocol_count();
36*b4734308SPeng Fan 	struct scmi_protocol_attributes_p2a return_values = {
37*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
38*b4734308SPeng Fan 		/* Null agent count since agent discovery is not supported */
39*b4734308SPeng Fan 		.attributes = SCMI_BASE_PROTOCOL_ATTRIBUTES(protocol_count, 0U),
40*b4734308SPeng Fan 	};
41*b4734308SPeng Fan 
42*b4734308SPeng Fan 	if (msg->in_size != 0U) {
43*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
44*b4734308SPeng Fan 		return;
45*b4734308SPeng Fan 	}
46*b4734308SPeng Fan 
47*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
48*b4734308SPeng Fan }
49*b4734308SPeng Fan 
50*b4734308SPeng Fan static void report_message_attributes(struct scmi_msg *msg)
51*b4734308SPeng Fan {
52*b4734308SPeng Fan 	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
53*b4734308SPeng Fan 	struct scmi_protocol_message_attributes_p2a return_values = {
54*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
55*b4734308SPeng Fan 		/* For this protocol, attributes shall be zero */
56*b4734308SPeng Fan 		.attributes = 0U,
57*b4734308SPeng Fan 	};
58*b4734308SPeng Fan 
59*b4734308SPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
60*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
61*b4734308SPeng Fan 		return;
62*b4734308SPeng Fan 	}
63*b4734308SPeng Fan 
64*b4734308SPeng Fan 	if (!message_id_is_supported(in_args->message_id)) {
65*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_NOT_FOUND);
66*b4734308SPeng Fan 		return;
67*b4734308SPeng Fan 	}
68*b4734308SPeng Fan 
69*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
70*b4734308SPeng Fan }
71*b4734308SPeng Fan 
72*b4734308SPeng Fan static void discover_vendor(struct scmi_msg *msg)
73*b4734308SPeng Fan {
74*b4734308SPeng Fan 	const char *name = plat_scmi_vendor_name();
75*b4734308SPeng Fan 	struct scmi_base_discover_vendor_p2a return_values = {
76*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
77*b4734308SPeng Fan 	};
78*b4734308SPeng Fan 
79*b4734308SPeng Fan 	if (msg->in_size != 0U) {
80*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
81*b4734308SPeng Fan 		return;
82*b4734308SPeng Fan 	}
83*b4734308SPeng Fan 
84*b4734308SPeng Fan 	COPY_NAME_IDENTIFIER(return_values.vendor_identifier, name);
85*b4734308SPeng Fan 
86*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
87*b4734308SPeng Fan }
88*b4734308SPeng Fan 
89*b4734308SPeng Fan static void discover_sub_vendor(struct scmi_msg *msg)
90*b4734308SPeng Fan {
91*b4734308SPeng Fan 	const char *name = plat_scmi_sub_vendor_name();
92*b4734308SPeng Fan 	struct scmi_base_discover_sub_vendor_p2a return_values = {
93*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
94*b4734308SPeng Fan 	};
95*b4734308SPeng Fan 
96*b4734308SPeng Fan 	if (msg->in_size != 0U) {
97*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
98*b4734308SPeng Fan 		return;
99*b4734308SPeng Fan 	}
100*b4734308SPeng Fan 
101*b4734308SPeng Fan 	COPY_NAME_IDENTIFIER(return_values.sub_vendor_identifier, name);
102*b4734308SPeng Fan 
103*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
104*b4734308SPeng Fan }
105*b4734308SPeng Fan 
106*b4734308SPeng Fan static void discover_implementation_version(struct scmi_msg *msg)
107*b4734308SPeng Fan {
108*b4734308SPeng Fan 	struct scmi_protocol_version_p2a return_values = {
109*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
110*b4734308SPeng Fan 		.version = SCMI_IMPL_VERSION,
111*b4734308SPeng Fan 	};
112*b4734308SPeng Fan 
113*b4734308SPeng Fan 	if (msg->in_size != 0U) {
114*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
115*b4734308SPeng Fan 		return;
116*b4734308SPeng Fan 	}
117*b4734308SPeng Fan 
118*b4734308SPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
119*b4734308SPeng Fan }
120*b4734308SPeng Fan 
121*b4734308SPeng Fan static unsigned int count_protocols_in_list(const uint8_t *protocol_list)
122*b4734308SPeng Fan {
123*b4734308SPeng Fan 	unsigned int count = 0U;
124*b4734308SPeng Fan 
125*b4734308SPeng Fan 	if (protocol_list != NULL) {
126*b4734308SPeng Fan 		while (protocol_list[count] != 0U) {
127*b4734308SPeng Fan 			count++;
128*b4734308SPeng Fan 		}
129*b4734308SPeng Fan 	}
130*b4734308SPeng Fan 
131*b4734308SPeng Fan 	return count;
132*b4734308SPeng Fan }
133*b4734308SPeng Fan 
134*b4734308SPeng Fan #define MAX_PROTOCOL_IN_LIST		8U
135*b4734308SPeng Fan 
136*b4734308SPeng Fan static void discover_list_protocols(struct scmi_msg *msg)
137*b4734308SPeng Fan {
138*b4734308SPeng Fan 	const struct scmi_base_discover_list_protocols_a2p *a2p = NULL;
139*b4734308SPeng Fan 	struct scmi_base_discover_list_protocols_p2a p2a = {
140*b4734308SPeng Fan 		.status = SCMI_SUCCESS,
141*b4734308SPeng Fan 	};
142*b4734308SPeng Fan 	uint8_t outargs[sizeof(p2a) + MAX_PROTOCOL_IN_LIST] = { 0U };
143*b4734308SPeng Fan 	const uint8_t *list = NULL;
144*b4734308SPeng Fan 	unsigned int count = 0U;
145*b4734308SPeng Fan 
146*b4734308SPeng Fan 	if (msg->in_size != sizeof(*a2p)) {
147*b4734308SPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
148*b4734308SPeng Fan 		return;
149*b4734308SPeng Fan 	}
150*b4734308SPeng Fan 
151*b4734308SPeng Fan 	assert(msg->out_size > sizeof(outargs));
152*b4734308SPeng Fan 
153*b4734308SPeng Fan 	a2p = (void *)msg->in;
154*b4734308SPeng Fan 
155*b4734308SPeng Fan 	list = plat_scmi_protocol_list(msg->agent_id);
156*b4734308SPeng Fan 	count = count_protocols_in_list(list);
157*b4734308SPeng Fan 	if (count > a2p->skip) {
158*b4734308SPeng Fan 		count = MIN(count - a2p->skip, MAX_PROTOCOL_IN_LIST);
159*b4734308SPeng Fan 	} else {
160*b4734308SPeng Fan 		count = 0U;
161*b4734308SPeng Fan 	}
162*b4734308SPeng Fan 
163*b4734308SPeng Fan 	p2a.num_protocols = count;
164*b4734308SPeng Fan 
165*b4734308SPeng Fan 	memcpy(outargs, &p2a, sizeof(p2a));
166*b4734308SPeng Fan 	memcpy(outargs + sizeof(p2a), list + a2p->skip, count);
167*b4734308SPeng Fan 
168*b4734308SPeng Fan 	scmi_write_response(msg, outargs, sizeof(outargs));
169*b4734308SPeng Fan }
170*b4734308SPeng Fan 
171*b4734308SPeng Fan static const scmi_msg_handler_t scmi_base_handler_table[] = {
172*b4734308SPeng Fan 	[SCMI_PROTOCOL_VERSION] = report_version,
173*b4734308SPeng Fan 	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
174*b4734308SPeng Fan 	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
175*b4734308SPeng Fan 	[SCMI_BASE_DISCOVER_VENDOR] = discover_vendor,
176*b4734308SPeng Fan 	[SCMI_BASE_DISCOVER_SUB_VENDOR] = discover_sub_vendor,
177*b4734308SPeng Fan 	[SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION] =
178*b4734308SPeng Fan 					discover_implementation_version,
179*b4734308SPeng Fan 	[SCMI_BASE_DISCOVER_LIST_PROTOCOLS] = discover_list_protocols,
180*b4734308SPeng Fan };
181*b4734308SPeng Fan 
182*b4734308SPeng Fan static bool message_id_is_supported(unsigned int message_id)
183*b4734308SPeng Fan {
184*b4734308SPeng Fan 	return (message_id < ARRAY_SIZE(scmi_base_handler_table)) &&
185*b4734308SPeng Fan 	       (scmi_base_handler_table[message_id] != NULL);
186*b4734308SPeng Fan }
187*b4734308SPeng Fan 
188*b4734308SPeng Fan scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg)
189*b4734308SPeng Fan {
190*b4734308SPeng Fan 	unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
191*b4734308SPeng Fan 
192*b4734308SPeng Fan 	if (message_id >= ARRAY_SIZE(scmi_base_handler_table)) {
193*b4734308SPeng Fan 		VERBOSE("Base handle not found %u\n", msg->message_id);
194*b4734308SPeng Fan 		return NULL;
195*b4734308SPeng Fan 	}
196*b4734308SPeng Fan 
197*b4734308SPeng Fan 	return scmi_base_handler_table[message_id];
198*b4734308SPeng Fan }
199