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