1*b4734308SPeng Fan // SPDX-License-Identifier: BSD-3-Clause 2*b4734308SPeng Fan /* 3*b4734308SPeng Fan * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. 4*b4734308SPeng Fan * Copyright (c) 2019-2020, Linaro Limited 5*b4734308SPeng Fan */ 6*b4734308SPeng Fan #include <assert.h> 7*b4734308SPeng Fan #include <string.h> 8*b4734308SPeng Fan 9*b4734308SPeng Fan #include <drivers/scmi-msg.h> 10*b4734308SPeng Fan #include <drivers/scmi.h> 11*b4734308SPeng Fan #include <lib/utils.h> 12*b4734308SPeng Fan #include <lib/utils_def.h> 13*b4734308SPeng Fan 14*b4734308SPeng Fan #include "common.h" 15*b4734308SPeng Fan 16*b4734308SPeng Fan static bool message_id_is_supported(unsigned int message_id); 17*b4734308SPeng Fan 18*b4734308SPeng Fan static void report_version(struct scmi_msg *msg) 19*b4734308SPeng Fan { 20*b4734308SPeng Fan struct scmi_protocol_version_p2a return_values = { 21*b4734308SPeng Fan .status = SCMI_SUCCESS, 22*b4734308SPeng Fan .version = SCMI_PROTOCOL_VERSION_BASE, 23*b4734308SPeng Fan }; 24*b4734308SPeng Fan 25*b4734308SPeng Fan if (msg->in_size != 0U) { 26*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 27*b4734308SPeng Fan return; 28*b4734308SPeng Fan } 29*b4734308SPeng Fan 30*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 31*b4734308SPeng Fan } 32*b4734308SPeng Fan 33*b4734308SPeng Fan static void report_attributes(struct scmi_msg *msg) 34*b4734308SPeng Fan { 35*b4734308SPeng Fan size_t protocol_count = plat_scmi_protocol_count(); 36*b4734308SPeng Fan struct scmi_protocol_attributes_p2a return_values = { 37*b4734308SPeng Fan .status = SCMI_SUCCESS, 38*b4734308SPeng Fan /* Null agent count since agent discovery is not supported */ 39*b4734308SPeng Fan .attributes = SCMI_BASE_PROTOCOL_ATTRIBUTES(protocol_count, 0U), 40*b4734308SPeng Fan }; 41*b4734308SPeng Fan 42*b4734308SPeng Fan if (msg->in_size != 0U) { 43*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 44*b4734308SPeng Fan return; 45*b4734308SPeng Fan } 46*b4734308SPeng Fan 47*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 48*b4734308SPeng Fan } 49*b4734308SPeng Fan 50*b4734308SPeng Fan static void report_message_attributes(struct scmi_msg *msg) 51*b4734308SPeng Fan { 52*b4734308SPeng Fan struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in; 53*b4734308SPeng Fan struct scmi_protocol_message_attributes_p2a return_values = { 54*b4734308SPeng Fan .status = SCMI_SUCCESS, 55*b4734308SPeng Fan /* For this protocol, attributes shall be zero */ 56*b4734308SPeng Fan .attributes = 0U, 57*b4734308SPeng Fan }; 58*b4734308SPeng Fan 59*b4734308SPeng Fan if (msg->in_size != sizeof(*in_args)) { 60*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 61*b4734308SPeng Fan return; 62*b4734308SPeng Fan } 63*b4734308SPeng Fan 64*b4734308SPeng Fan if (!message_id_is_supported(in_args->message_id)) { 65*b4734308SPeng Fan scmi_status_response(msg, SCMI_NOT_FOUND); 66*b4734308SPeng Fan return; 67*b4734308SPeng Fan } 68*b4734308SPeng Fan 69*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 70*b4734308SPeng Fan } 71*b4734308SPeng Fan 72*b4734308SPeng Fan static void discover_vendor(struct scmi_msg *msg) 73*b4734308SPeng Fan { 74*b4734308SPeng Fan const char *name = plat_scmi_vendor_name(); 75*b4734308SPeng Fan struct scmi_base_discover_vendor_p2a return_values = { 76*b4734308SPeng Fan .status = SCMI_SUCCESS, 77*b4734308SPeng Fan }; 78*b4734308SPeng Fan 79*b4734308SPeng Fan if (msg->in_size != 0U) { 80*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 81*b4734308SPeng Fan return; 82*b4734308SPeng Fan } 83*b4734308SPeng Fan 84*b4734308SPeng Fan COPY_NAME_IDENTIFIER(return_values.vendor_identifier, name); 85*b4734308SPeng Fan 86*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 87*b4734308SPeng Fan } 88*b4734308SPeng Fan 89*b4734308SPeng Fan static void discover_sub_vendor(struct scmi_msg *msg) 90*b4734308SPeng Fan { 91*b4734308SPeng Fan const char *name = plat_scmi_sub_vendor_name(); 92*b4734308SPeng Fan struct scmi_base_discover_sub_vendor_p2a return_values = { 93*b4734308SPeng Fan .status = SCMI_SUCCESS, 94*b4734308SPeng Fan }; 95*b4734308SPeng Fan 96*b4734308SPeng Fan if (msg->in_size != 0U) { 97*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 98*b4734308SPeng Fan return; 99*b4734308SPeng Fan } 100*b4734308SPeng Fan 101*b4734308SPeng Fan COPY_NAME_IDENTIFIER(return_values.sub_vendor_identifier, name); 102*b4734308SPeng Fan 103*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 104*b4734308SPeng Fan } 105*b4734308SPeng Fan 106*b4734308SPeng Fan static void discover_implementation_version(struct scmi_msg *msg) 107*b4734308SPeng Fan { 108*b4734308SPeng Fan struct scmi_protocol_version_p2a return_values = { 109*b4734308SPeng Fan .status = SCMI_SUCCESS, 110*b4734308SPeng Fan .version = SCMI_IMPL_VERSION, 111*b4734308SPeng Fan }; 112*b4734308SPeng Fan 113*b4734308SPeng Fan if (msg->in_size != 0U) { 114*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 115*b4734308SPeng Fan return; 116*b4734308SPeng Fan } 117*b4734308SPeng Fan 118*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 119*b4734308SPeng Fan } 120*b4734308SPeng Fan 121*b4734308SPeng Fan static unsigned int count_protocols_in_list(const uint8_t *protocol_list) 122*b4734308SPeng Fan { 123*b4734308SPeng Fan unsigned int count = 0U; 124*b4734308SPeng Fan 125*b4734308SPeng Fan if (protocol_list != NULL) { 126*b4734308SPeng Fan while (protocol_list[count] != 0U) { 127*b4734308SPeng Fan count++; 128*b4734308SPeng Fan } 129*b4734308SPeng Fan } 130*b4734308SPeng Fan 131*b4734308SPeng Fan return count; 132*b4734308SPeng Fan } 133*b4734308SPeng Fan 134*b4734308SPeng Fan #define MAX_PROTOCOL_IN_LIST 8U 135*b4734308SPeng Fan 136*b4734308SPeng Fan static void discover_list_protocols(struct scmi_msg *msg) 137*b4734308SPeng Fan { 138*b4734308SPeng Fan const struct scmi_base_discover_list_protocols_a2p *a2p = NULL; 139*b4734308SPeng Fan struct scmi_base_discover_list_protocols_p2a p2a = { 140*b4734308SPeng Fan .status = SCMI_SUCCESS, 141*b4734308SPeng Fan }; 142*b4734308SPeng Fan uint8_t outargs[sizeof(p2a) + MAX_PROTOCOL_IN_LIST] = { 0U }; 143*b4734308SPeng Fan const uint8_t *list = NULL; 144*b4734308SPeng Fan unsigned int count = 0U; 145*b4734308SPeng Fan 146*b4734308SPeng Fan if (msg->in_size != sizeof(*a2p)) { 147*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 148*b4734308SPeng Fan return; 149*b4734308SPeng Fan } 150*b4734308SPeng Fan 151*b4734308SPeng Fan assert(msg->out_size > sizeof(outargs)); 152*b4734308SPeng Fan 153*b4734308SPeng Fan a2p = (void *)msg->in; 154*b4734308SPeng Fan 155*b4734308SPeng Fan list = plat_scmi_protocol_list(msg->agent_id); 156*b4734308SPeng Fan count = count_protocols_in_list(list); 157*b4734308SPeng Fan if (count > a2p->skip) { 158*b4734308SPeng Fan count = MIN(count - a2p->skip, MAX_PROTOCOL_IN_LIST); 159*b4734308SPeng Fan } else { 160*b4734308SPeng Fan count = 0U; 161*b4734308SPeng Fan } 162*b4734308SPeng Fan 163*b4734308SPeng Fan p2a.num_protocols = count; 164*b4734308SPeng Fan 165*b4734308SPeng Fan memcpy(outargs, &p2a, sizeof(p2a)); 166*b4734308SPeng Fan memcpy(outargs + sizeof(p2a), list + a2p->skip, count); 167*b4734308SPeng Fan 168*b4734308SPeng Fan scmi_write_response(msg, outargs, sizeof(outargs)); 169*b4734308SPeng Fan } 170*b4734308SPeng Fan 171*b4734308SPeng Fan static const scmi_msg_handler_t scmi_base_handler_table[] = { 172*b4734308SPeng Fan [SCMI_PROTOCOL_VERSION] = report_version, 173*b4734308SPeng Fan [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes, 174*b4734308SPeng Fan [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes, 175*b4734308SPeng Fan [SCMI_BASE_DISCOVER_VENDOR] = discover_vendor, 176*b4734308SPeng Fan [SCMI_BASE_DISCOVER_SUB_VENDOR] = discover_sub_vendor, 177*b4734308SPeng Fan [SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION] = 178*b4734308SPeng Fan discover_implementation_version, 179*b4734308SPeng Fan [SCMI_BASE_DISCOVER_LIST_PROTOCOLS] = discover_list_protocols, 180*b4734308SPeng Fan }; 181*b4734308SPeng Fan 182*b4734308SPeng Fan static bool message_id_is_supported(unsigned int message_id) 183*b4734308SPeng Fan { 184*b4734308SPeng Fan return (message_id < ARRAY_SIZE(scmi_base_handler_table)) && 185*b4734308SPeng Fan (scmi_base_handler_table[message_id] != NULL); 186*b4734308SPeng Fan } 187*b4734308SPeng Fan 188*b4734308SPeng Fan scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg) 189*b4734308SPeng Fan { 190*b4734308SPeng Fan unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id); 191*b4734308SPeng Fan 192*b4734308SPeng Fan if (message_id >= ARRAY_SIZE(scmi_base_handler_table)) { 193*b4734308SPeng Fan VERBOSE("Base handle not found %u\n", msg->message_id); 194*b4734308SPeng Fan return NULL; 195*b4734308SPeng Fan } 196*b4734308SPeng Fan 197*b4734308SPeng Fan return scmi_base_handler_table[message_id]; 198*b4734308SPeng Fan } 199