xref: /rk3399_ARM-atf/drivers/scmi-msg/power_domain.c (revision 35e6c408f87772a27566ff2d9afcb5fb189f6ab5)
17e4833cdSPeng Fan // SPDX-License-Identifier: BSD-3-Clause
27e4833cdSPeng Fan /*
37e4833cdSPeng Fan  * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
47e4833cdSPeng Fan  * Copyright (c) 2019-2020, Linaro Limited
57e4833cdSPeng Fan  */
67e4833cdSPeng Fan #include <cdefs.h>
77e4833cdSPeng Fan #include <string.h>
87e4833cdSPeng Fan 
97e4833cdSPeng Fan #include <drivers/scmi-msg.h>
107e4833cdSPeng Fan #include <drivers/scmi.h>
117e4833cdSPeng Fan #include <lib/utils_def.h>
127e4833cdSPeng Fan 
137e4833cdSPeng Fan #include "common.h"
147e4833cdSPeng Fan 
157e4833cdSPeng Fan #pragma weak plat_scmi_pd_count
167e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_name
177e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_state
187e4833cdSPeng Fan #pragma weak plat_scmi_pd_set_state
197e4833cdSPeng Fan #pragma weak plat_scmi_pd_statistics
207e4833cdSPeng Fan #pragma weak plat_scmi_pd_get_attributes
217e4833cdSPeng Fan 
222355ebffSSchspa Shi static bool message_id_is_supported(unsigned int message_id);
237e4833cdSPeng Fan 
plat_scmi_pd_count(unsigned int agent_id __unused)247e4833cdSPeng Fan size_t plat_scmi_pd_count(unsigned int agent_id __unused)
257e4833cdSPeng Fan {
267e4833cdSPeng Fan 	return 0U;
277e4833cdSPeng Fan }
287e4833cdSPeng Fan 
plat_scmi_pd_get_name(unsigned int agent_id __unused,unsigned int pd_id __unused)297e4833cdSPeng Fan const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
307e4833cdSPeng Fan 				  unsigned int pd_id __unused)
317e4833cdSPeng Fan {
327e4833cdSPeng Fan 	return NULL;
337e4833cdSPeng Fan }
347e4833cdSPeng Fan 
plat_scmi_pd_statistics(unsigned int agent_id __unused,unsigned long * pd_id __unused)357e4833cdSPeng Fan unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused,
367e4833cdSPeng Fan 				     unsigned long *pd_id __unused)
377e4833cdSPeng Fan {
387e4833cdSPeng Fan 	return 0U;
397e4833cdSPeng Fan }
407e4833cdSPeng Fan 
plat_scmi_pd_get_attributes(unsigned int agent_id __unused,unsigned int pd_id __unused)417e4833cdSPeng Fan unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused,
427e4833cdSPeng Fan 					 unsigned int pd_id __unused)
437e4833cdSPeng Fan {
447e4833cdSPeng Fan 	return 0U;
457e4833cdSPeng Fan }
467e4833cdSPeng Fan 
plat_scmi_pd_get_state(unsigned int agent_id __unused,unsigned int pd_id __unused)477e4833cdSPeng Fan unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
487e4833cdSPeng Fan 				    unsigned int pd_id __unused)
497e4833cdSPeng Fan {
507e4833cdSPeng Fan 	return 0U;
517e4833cdSPeng Fan }
527e4833cdSPeng Fan 
plat_scmi_pd_set_state(unsigned int agent_id __unused,unsigned int flags __unused,unsigned int pd_id __unused,unsigned int state __unused)537e4833cdSPeng Fan int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
547e4833cdSPeng Fan 			       unsigned int flags __unused,
557e4833cdSPeng Fan 			       unsigned int pd_id __unused,
567e4833cdSPeng Fan 			       unsigned int state __unused)
577e4833cdSPeng Fan {
587e4833cdSPeng Fan 	return SCMI_NOT_SUPPORTED;
597e4833cdSPeng Fan }
607e4833cdSPeng Fan 
report_version(struct scmi_msg * msg)617e4833cdSPeng Fan static void report_version(struct scmi_msg *msg)
627e4833cdSPeng Fan {
637e4833cdSPeng Fan 	struct scmi_protocol_version_p2a return_values = {
647e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
657e4833cdSPeng Fan 		.version = SCMI_PROTOCOL_VERSION_PD,
667e4833cdSPeng Fan 	};
677e4833cdSPeng Fan 
687e4833cdSPeng Fan 	if (msg->in_size != 0) {
697e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
707e4833cdSPeng Fan 		return;
717e4833cdSPeng Fan 	}
727e4833cdSPeng Fan 
737e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
747e4833cdSPeng Fan }
757e4833cdSPeng Fan 
report_attributes(struct scmi_msg * msg)767e4833cdSPeng Fan static void report_attributes(struct scmi_msg *msg)
777e4833cdSPeng Fan {
787e4833cdSPeng Fan 	unsigned long addr = 0UL;
797e4833cdSPeng Fan 	unsigned int len;
807e4833cdSPeng Fan 
817e4833cdSPeng Fan 	struct scmi_protocol_attributes_p2a_pd return_values = {
827e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
837e4833cdSPeng Fan 	};
847e4833cdSPeng Fan 
857e4833cdSPeng Fan 	if (msg->in_size != 0) {
867e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
877e4833cdSPeng Fan 		return;
887e4833cdSPeng Fan 	}
897e4833cdSPeng Fan 
907e4833cdSPeng Fan 	return_values.attributes = plat_scmi_pd_count(msg->agent_id);
917e4833cdSPeng Fan 	len = plat_scmi_pd_statistics(msg->agent_id, &addr);
927e4833cdSPeng Fan 	if (len != 0U) {
937e4833cdSPeng Fan 		return_values.statistics_addr_low = (unsigned int)addr;
947e4833cdSPeng Fan 		return_values.statistics_addr_high = (uint32_t)(addr >> 32);
957e4833cdSPeng Fan 		return_values.statistics_len = len;
967e4833cdSPeng Fan 	}
977e4833cdSPeng Fan 
987e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
997e4833cdSPeng Fan }
1007e4833cdSPeng Fan 
report_message_attributes(struct scmi_msg * msg)1017e4833cdSPeng Fan static void report_message_attributes(struct scmi_msg *msg)
1027e4833cdSPeng Fan {
1037e4833cdSPeng Fan 	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
1047e4833cdSPeng Fan 	struct scmi_protocol_message_attributes_p2a return_values = {
1057e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
1067e4833cdSPeng Fan 		/* For this protocol, attributes shall be zero */
1077e4833cdSPeng Fan 		.attributes = 0U,
1087e4833cdSPeng Fan 	};
1097e4833cdSPeng Fan 
1107e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
1117e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
1127e4833cdSPeng Fan 		return;
1137e4833cdSPeng Fan 	}
1147e4833cdSPeng Fan 
1157e4833cdSPeng Fan 	if (!message_id_is_supported(in_args->message_id)) {
1167e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_NOT_FOUND);
1177e4833cdSPeng Fan 		return;
1187e4833cdSPeng Fan 	}
1197e4833cdSPeng Fan 
1207e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
1217e4833cdSPeng Fan }
1227e4833cdSPeng Fan 
scmi_pd_attributes(struct scmi_msg * msg)1237e4833cdSPeng Fan static void scmi_pd_attributes(struct scmi_msg *msg)
1247e4833cdSPeng Fan {
1257e4833cdSPeng Fan 	const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in;
1267e4833cdSPeng Fan 	struct scmi_pd_attributes_p2a return_values = {
1277e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
1287e4833cdSPeng Fan 	};
1297e4833cdSPeng Fan 	const char *name = NULL;
1307e4833cdSPeng Fan 	unsigned int pd_id = 0U;
1317e4833cdSPeng Fan 
1327e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
1337e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
1347e4833cdSPeng Fan 		return;
1357e4833cdSPeng Fan 	}
1367e4833cdSPeng Fan 
1377e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
1387e4833cdSPeng Fan 
1397e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
140*48ec8d33Sscaria 		scmi_status_response(msg, SCMI_NOT_FOUND);
1417e4833cdSPeng Fan 		return;
1427e4833cdSPeng Fan 	}
1437e4833cdSPeng Fan 
1447e4833cdSPeng Fan 	name = plat_scmi_pd_get_name(msg->agent_id, pd_id);
1457e4833cdSPeng Fan 	if (name == NULL) {
1467e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_NOT_FOUND);
1477e4833cdSPeng Fan 		return;
1487e4833cdSPeng Fan 	}
1497e4833cdSPeng Fan 
1507e4833cdSPeng Fan 	COPY_NAME_IDENTIFIER(return_values.pd_name, name);
1517e4833cdSPeng Fan 
1527e4833cdSPeng Fan 	return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id);
1537e4833cdSPeng Fan 
1547e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
1557e4833cdSPeng Fan }
1567e4833cdSPeng Fan 
scmi_pd_state_get(struct scmi_msg * msg)1577e4833cdSPeng Fan static void scmi_pd_state_get(struct scmi_msg *msg)
1587e4833cdSPeng Fan {
1597e4833cdSPeng Fan 	const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in;
1607e4833cdSPeng Fan 	unsigned int state = 0U;
1617e4833cdSPeng Fan 	struct scmi_pd_state_get_p2a return_values = {
1627e4833cdSPeng Fan 		.status = SCMI_SUCCESS,
1637e4833cdSPeng Fan 	};
1647e4833cdSPeng Fan 	unsigned int pd_id = 0U;
1657e4833cdSPeng Fan 
1667e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
1677e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
1687e4833cdSPeng Fan 		return;
1697e4833cdSPeng Fan 	}
1707e4833cdSPeng Fan 
1717e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
1727e4833cdSPeng Fan 
1737e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
174*48ec8d33Sscaria 		scmi_status_response(msg, SCMI_NOT_FOUND);
1757e4833cdSPeng Fan 		return;
1767e4833cdSPeng Fan 	}
1777e4833cdSPeng Fan 
1787e4833cdSPeng Fan 	state = plat_scmi_pd_get_state(msg->agent_id, pd_id);
1797e4833cdSPeng Fan 
1807e4833cdSPeng Fan 	return_values.power_state = state;
1817e4833cdSPeng Fan 
1827e4833cdSPeng Fan 	scmi_write_response(msg, &return_values, sizeof(return_values));
1837e4833cdSPeng Fan }
1847e4833cdSPeng Fan 
scmi_pd_state_set(struct scmi_msg * msg)1857e4833cdSPeng Fan static void scmi_pd_state_set(struct scmi_msg *msg)
1867e4833cdSPeng Fan {
1877e4833cdSPeng Fan 	const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in;
1887e4833cdSPeng Fan 	unsigned int flags = 0U;
1897e4833cdSPeng Fan 	int32_t status = 0;
1907e4833cdSPeng Fan 	unsigned int pd_id = 0U;
1917e4833cdSPeng Fan 	unsigned int state = 0U;
1927e4833cdSPeng Fan 
1937e4833cdSPeng Fan 	if (msg->in_size != sizeof(*in_args)) {
1947e4833cdSPeng Fan 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
1957e4833cdSPeng Fan 		return;
1967e4833cdSPeng Fan 	}
1977e4833cdSPeng Fan 
1987e4833cdSPeng Fan 	pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
1997e4833cdSPeng Fan 
2007e4833cdSPeng Fan 	if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
201*48ec8d33Sscaria 		scmi_status_response(msg, SCMI_NOT_FOUND);
2027e4833cdSPeng Fan 		return;
2037e4833cdSPeng Fan 	}
2047e4833cdSPeng Fan 
2057e4833cdSPeng Fan 	flags = SPECULATION_SAFE_VALUE(in_args->flags);
2067e4833cdSPeng Fan 	state = SPECULATION_SAFE_VALUE(in_args->power_state);
2077e4833cdSPeng Fan 
2087e4833cdSPeng Fan 	status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state);
2097e4833cdSPeng Fan 
2107e4833cdSPeng Fan 	scmi_status_response(msg, status);
2117e4833cdSPeng Fan }
2127e4833cdSPeng Fan 
2137e4833cdSPeng Fan static const scmi_msg_handler_t scmi_pd_handler_table[] = {
2147e4833cdSPeng Fan 	[SCMI_PROTOCOL_VERSION] = report_version,
2157e4833cdSPeng Fan 	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
2167e4833cdSPeng Fan 	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
2177e4833cdSPeng Fan 	[SCMI_PD_ATTRIBUTES] = scmi_pd_attributes,
2187e4833cdSPeng Fan 	[SCMI_PD_STATE_SET] = scmi_pd_state_set,
2197e4833cdSPeng Fan 	[SCMI_PD_STATE_GET] = scmi_pd_state_get,
2207e4833cdSPeng Fan };
2217e4833cdSPeng Fan 
message_id_is_supported(unsigned int message_id)2222355ebffSSchspa Shi static bool message_id_is_supported(unsigned int message_id)
2237e4833cdSPeng Fan {
2247e4833cdSPeng Fan 	return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) &&
2257e4833cdSPeng Fan 	       (scmi_pd_handler_table[message_id] != NULL);
2267e4833cdSPeng Fan }
2277e4833cdSPeng Fan 
scmi_msg_get_pd_handler(struct scmi_msg * msg)2287e4833cdSPeng Fan scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg)
2297e4833cdSPeng Fan {
2307e4833cdSPeng Fan 	const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table);
2317e4833cdSPeng Fan 	unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
2327e4833cdSPeng Fan 
2337e4833cdSPeng Fan 	if (message_id >= array_size) {
2347e4833cdSPeng Fan 		VERBOSE("pd handle not found %u", msg->message_id);
2357e4833cdSPeng Fan 		return NULL;
2367e4833cdSPeng Fan 	}
2377e4833cdSPeng Fan 
2387e4833cdSPeng Fan 	return scmi_pd_handler_table[message_id];
2397e4833cdSPeng Fan }
240