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