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 247e4833cdSPeng Fan size_t plat_scmi_pd_count(unsigned int agent_id __unused) 257e4833cdSPeng Fan { 267e4833cdSPeng Fan return 0U; 277e4833cdSPeng Fan } 287e4833cdSPeng Fan 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 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 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 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 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 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 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 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 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 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 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 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 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