xref: /rk3399_ARM-atf/drivers/scmi-msg/power_domain.c (revision 7e4833cdde8235d228f1f1c40f52b989ad5aa98a)
1*7e4833cdSPeng Fan // SPDX-License-Identifier: BSD-3-Clause
2*7e4833cdSPeng Fan /*
3*7e4833cdSPeng Fan  * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
4*7e4833cdSPeng Fan  * Copyright (c) 2019-2020, Linaro Limited
5*7e4833cdSPeng Fan  */
6*7e4833cdSPeng Fan #include <cdefs.h>
7*7e4833cdSPeng Fan #include <string.h>
8*7e4833cdSPeng Fan 
9*7e4833cdSPeng Fan #include <drivers/scmi-msg.h>
10*7e4833cdSPeng Fan #include <drivers/scmi.h>
11*7e4833cdSPeng Fan #include <lib/utils_def.h>
12*7e4833cdSPeng Fan 
13*7e4833cdSPeng Fan #include "common.h"
14*7e4833cdSPeng Fan 
15*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_count
16*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_name
17*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_state
18*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_set_state
19*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_statistics
20*7e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_attributes
21*7e4833cdSPeng Fan 
22*7e4833cdSPeng Fan static bool message_id_is_supported(size_t message_id);
23*7e4833cdSPeng Fan 
24*7e4833cdSPeng Fan size_t plat_scmi_pd_count(unsigned int agent_id __unused)
25*7e4833cdSPeng Fan {
26*7e4833cdSPeng Fan 	return 0U;
27*7e4833cdSPeng Fan }
28*7e4833cdSPeng Fan 
29*7e4833cdSPeng Fan const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
30*7e4833cdSPeng Fan 				  unsigned int pd_id __unused)
31*7e4833cdSPeng Fan {
32*7e4833cdSPeng Fan 	return NULL;
33*7e4833cdSPeng Fan }
34*7e4833cdSPeng Fan 
35*7e4833cdSPeng Fan unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused,
36*7e4833cdSPeng Fan 				     unsigned long *pd_id __unused)
37*7e4833cdSPeng Fan {
38*7e4833cdSPeng Fan 	return 0U;
39*7e4833cdSPeng Fan }
40*7e4833cdSPeng Fan 
41*7e4833cdSPeng Fan unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused,
42*7e4833cdSPeng Fan 					 unsigned int pd_id __unused)
43*7e4833cdSPeng Fan {
44*7e4833cdSPeng Fan 	return 0U;
45*7e4833cdSPeng Fan }
46*7e4833cdSPeng Fan 
47*7e4833cdSPeng Fan unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
48*7e4833cdSPeng Fan 				    unsigned int pd_id __unused)
49*7e4833cdSPeng Fan {
50*7e4833cdSPeng Fan 	return 0U;
51*7e4833cdSPeng Fan }
52*7e4833cdSPeng Fan 
53*7e4833cdSPeng Fan int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
54*7e4833cdSPeng Fan 			       unsigned int flags __unused,
55*7e4833cdSPeng Fan 			       unsigned int pd_id __unused,
56*7e4833cdSPeng Fan 			       unsigned int state __unused)
57*7e4833cdSPeng Fan {
58*7e4833cdSPeng Fan 	return SCMI_NOT_SUPPORTED;
59*7e4833cdSPeng Fan }
60*7e4833cdSPeng Fan 
61*7e4833cdSPeng Fan static void report_version(struct scmi_msg *msg)
62*7e4833cdSPeng Fan {
63*7e4833cdSPeng Fan 	struct scmi_protocol_version_p2a return_values = {
64*7e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
65*7e4833cdSPeng Fan 		.version = SCMI_PROTOCOL_VERSION_PD,
66*7e4833cdSPeng Fan 	};
67*7e4833cdSPeng Fan 
68*7e4833cdSPeng Fan 	if (msg->in_size != 0) {
69*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
70*7e4833cdSPeng Fan 		return;
71*7e4833cdSPeng Fan 	}
72*7e4833cdSPeng Fan 
73*7e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
74*7e4833cdSPeng Fan }
75*7e4833cdSPeng Fan 
76*7e4833cdSPeng Fan static void report_attributes(struct scmi_msg *msg)
77*7e4833cdSPeng Fan {
78*7e4833cdSPeng Fan 	unsigned long addr = 0UL;
79*7e4833cdSPeng Fan 	unsigned int len;
80*7e4833cdSPeng Fan 
81*7e4833cdSPeng Fan 	struct scmi_protocol_attributes_p2a_pd return_values = {
82*7e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
83*7e4833cdSPeng Fan 	};
84*7e4833cdSPeng Fan 
85*7e4833cdSPeng Fan 	if (msg->in_size != 0) {
86*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
87*7e4833cdSPeng Fan 		return;
88*7e4833cdSPeng Fan 	}
89*7e4833cdSPeng Fan 
90*7e4833cdSPeng Fan 	return_values.attributes = plat_scmi_pd_count(msg->agent_id);
91*7e4833cdSPeng Fan 	len = plat_scmi_pd_statistics(msg->agent_id, &addr);
92*7e4833cdSPeng Fan 	if (len != 0U) {
93*7e4833cdSPeng Fan 		return_values.statistics_addr_low = (unsigned int)addr;
94*7e4833cdSPeng Fan 		return_values.statistics_addr_high = (uint32_t)(addr >> 32);
95*7e4833cdSPeng Fan 		return_values.statistics_len = len;
96*7e4833cdSPeng Fan 	}
97*7e4833cdSPeng Fan 
98*7e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
99*7e4833cdSPeng Fan }
100*7e4833cdSPeng Fan 
101*7e4833cdSPeng Fan static void report_message_attributes(struct scmi_msg *msg)
102*7e4833cdSPeng Fan {
103*7e4833cdSPeng Fan 	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
104*7e4833cdSPeng Fan 	struct scmi_protocol_message_attributes_p2a return_values = {
105*7e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
106*7e4833cdSPeng Fan 		/* For this protocol, attributes shall be zero */
107*7e4833cdSPeng Fan 		.attributes = 0U,
108*7e4833cdSPeng Fan 	};
109*7e4833cdSPeng Fan 
110*7e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
111*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
112*7e4833cdSPeng Fan 		return;
113*7e4833cdSPeng Fan 	}
114*7e4833cdSPeng Fan 
115*7e4833cdSPeng Fan 	if (!message_id_is_supported(in_args->message_id)) {
116*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_NOT_FOUND);
117*7e4833cdSPeng Fan 		return;
118*7e4833cdSPeng Fan 	}
119*7e4833cdSPeng Fan 
120*7e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
121*7e4833cdSPeng Fan }
122*7e4833cdSPeng Fan 
123*7e4833cdSPeng Fan static void scmi_pd_attributes(struct scmi_msg *msg)
124*7e4833cdSPeng Fan {
125*7e4833cdSPeng Fan 	const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in;
126*7e4833cdSPeng Fan 	struct scmi_pd_attributes_p2a return_values = {
127*7e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
128*7e4833cdSPeng Fan 	};
129*7e4833cdSPeng Fan 	const char *name = NULL;
130*7e4833cdSPeng Fan 	unsigned int pd_id = 0U;
131*7e4833cdSPeng Fan 
132*7e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
133*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
134*7e4833cdSPeng Fan 		return;
135*7e4833cdSPeng Fan 	}
136*7e4833cdSPeng Fan 
137*7e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
138*7e4833cdSPeng Fan 
139*7e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
140*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
141*7e4833cdSPeng Fan 		return;
142*7e4833cdSPeng Fan 	}
143*7e4833cdSPeng Fan 
144*7e4833cdSPeng Fan 	name = plat_scmi_pd_get_name(msg->agent_id, pd_id);
145*7e4833cdSPeng Fan 	if (name == NULL) {
146*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_NOT_FOUND);
147*7e4833cdSPeng Fan 		return;
148*7e4833cdSPeng Fan 	}
149*7e4833cdSPeng Fan 
150*7e4833cdSPeng Fan 	COPY_NAME_IDENTIFIER(return_values.pd_name, name);
151*7e4833cdSPeng Fan 
152*7e4833cdSPeng Fan 	return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id);
153*7e4833cdSPeng Fan 
154*7e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
155*7e4833cdSPeng Fan }
156*7e4833cdSPeng Fan 
157*7e4833cdSPeng Fan static void scmi_pd_state_get(struct scmi_msg *msg)
158*7e4833cdSPeng Fan {
159*7e4833cdSPeng Fan 	const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in;
160*7e4833cdSPeng Fan 	unsigned int state = 0U;
161*7e4833cdSPeng Fan 	struct scmi_pd_state_get_p2a return_values = {
162*7e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
163*7e4833cdSPeng Fan 	};
164*7e4833cdSPeng Fan 	unsigned int pd_id = 0U;
165*7e4833cdSPeng Fan 
166*7e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
167*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
168*7e4833cdSPeng Fan 		return;
169*7e4833cdSPeng Fan 	}
170*7e4833cdSPeng Fan 
171*7e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
172*7e4833cdSPeng Fan 
173*7e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
174*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
175*7e4833cdSPeng Fan 		return;
176*7e4833cdSPeng Fan 	}
177*7e4833cdSPeng Fan 
178*7e4833cdSPeng Fan 	state = plat_scmi_pd_get_state(msg->agent_id, pd_id);
179*7e4833cdSPeng Fan 
180*7e4833cdSPeng Fan 	return_values.power_state = state;
181*7e4833cdSPeng Fan 
182*7e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
183*7e4833cdSPeng Fan }
184*7e4833cdSPeng Fan 
185*7e4833cdSPeng Fan static void scmi_pd_state_set(struct scmi_msg *msg)
186*7e4833cdSPeng Fan {
187*7e4833cdSPeng Fan 	const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in;
188*7e4833cdSPeng Fan 	unsigned int flags = 0U;
189*7e4833cdSPeng Fan 	int32_t status = 0;
190*7e4833cdSPeng Fan 	unsigned int pd_id = 0U;
191*7e4833cdSPeng Fan 	unsigned int state = 0U;
192*7e4833cdSPeng Fan 
193*7e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
194*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
195*7e4833cdSPeng Fan 		return;
196*7e4833cdSPeng Fan 	}
197*7e4833cdSPeng Fan 
198*7e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
199*7e4833cdSPeng Fan 
200*7e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
201*7e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
202*7e4833cdSPeng Fan 		return;
203*7e4833cdSPeng Fan 	}
204*7e4833cdSPeng Fan 
205*7e4833cdSPeng Fan 	flags = SPECULATION_SAFE_VALUE(in_args->flags);
206*7e4833cdSPeng Fan 	state = SPECULATION_SAFE_VALUE(in_args->power_state);
207*7e4833cdSPeng Fan 
208*7e4833cdSPeng Fan 	status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state);
209*7e4833cdSPeng Fan 
210*7e4833cdSPeng Fan 	scmi_status_response(msg, status);
211*7e4833cdSPeng Fan }
212*7e4833cdSPeng Fan 
213*7e4833cdSPeng Fan static const scmi_msg_handler_t scmi_pd_handler_table[] = {
214*7e4833cdSPeng Fan 	[SCMI_PROTOCOL_VERSION] = report_version,
215*7e4833cdSPeng Fan 	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
216*7e4833cdSPeng Fan 	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
217*7e4833cdSPeng Fan 	[SCMI_PD_ATTRIBUTES] = scmi_pd_attributes,
218*7e4833cdSPeng Fan 	[SCMI_PD_STATE_SET] = scmi_pd_state_set,
219*7e4833cdSPeng Fan 	[SCMI_PD_STATE_GET] = scmi_pd_state_get,
220*7e4833cdSPeng Fan };
221*7e4833cdSPeng Fan 
222*7e4833cdSPeng Fan static bool message_id_is_supported(size_t message_id)
223*7e4833cdSPeng Fan {
224*7e4833cdSPeng Fan 	return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) &&
225*7e4833cdSPeng Fan 	       (scmi_pd_handler_table[message_id] != NULL);
226*7e4833cdSPeng Fan }
227*7e4833cdSPeng Fan 
228*7e4833cdSPeng Fan scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg)
229*7e4833cdSPeng Fan {
230*7e4833cdSPeng Fan 	const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table);
231*7e4833cdSPeng Fan 	unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
232*7e4833cdSPeng Fan 
233*7e4833cdSPeng Fan 	if (message_id >= array_size) {
234*7e4833cdSPeng Fan 		VERBOSE("pd handle not found %u", msg->message_id);
235*7e4833cdSPeng Fan 		return NULL;
236*7e4833cdSPeng Fan 	}
237*7e4833cdSPeng Fan 
238*7e4833cdSPeng Fan 	return scmi_pd_handler_table[message_id];
239*7e4833cdSPeng Fan }
240