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