1*b4734308SPeng Fan // SPDX-License-Identifier: BSD-3-Clause 2*b4734308SPeng Fan /* 3*b4734308SPeng Fan * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. 4*b4734308SPeng Fan * Copyright (c) 2019-2020, Linaro Limited 5*b4734308SPeng Fan */ 6*b4734308SPeng Fan #include <cdefs.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 #pragma weak plat_scmi_rstd_count 19*b4734308SPeng Fan #pragma weak plat_scmi_rstd_get_name 20*b4734308SPeng Fan #pragma weak plat_scmi_rstd_autonomous 21*b4734308SPeng Fan #pragma weak plat_scmi_rstd_set_state 22*b4734308SPeng Fan 23*b4734308SPeng Fan size_t plat_scmi_rstd_count(unsigned int agent_id __unused) 24*b4734308SPeng Fan { 25*b4734308SPeng Fan return 0U; 26*b4734308SPeng Fan } 27*b4734308SPeng Fan 28*b4734308SPeng Fan const char *plat_scmi_rstd_get_name(unsigned int agent_id __unused, 29*b4734308SPeng Fan unsigned int scmi_id __unused) 30*b4734308SPeng Fan { 31*b4734308SPeng Fan return NULL; 32*b4734308SPeng Fan } 33*b4734308SPeng Fan 34*b4734308SPeng Fan int32_t plat_scmi_rstd_autonomous(unsigned int agent_id __unused, 35*b4734308SPeng Fan unsigned int scmi_id __unused, 36*b4734308SPeng Fan unsigned int state __unused) 37*b4734308SPeng Fan { 38*b4734308SPeng Fan return SCMI_NOT_SUPPORTED; 39*b4734308SPeng Fan } 40*b4734308SPeng Fan 41*b4734308SPeng Fan int32_t plat_scmi_rstd_set_state(unsigned int agent_id __unused, 42*b4734308SPeng Fan unsigned int scmi_id __unused, 43*b4734308SPeng Fan bool assert_not_deassert __unused) 44*b4734308SPeng Fan { 45*b4734308SPeng Fan return SCMI_NOT_SUPPORTED; 46*b4734308SPeng Fan } 47*b4734308SPeng Fan 48*b4734308SPeng Fan static void report_version(struct scmi_msg *msg) 49*b4734308SPeng Fan { 50*b4734308SPeng Fan struct scmi_protocol_version_p2a return_values = { 51*b4734308SPeng Fan .status = SCMI_SUCCESS, 52*b4734308SPeng Fan .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN, 53*b4734308SPeng Fan }; 54*b4734308SPeng Fan 55*b4734308SPeng Fan if (msg->in_size != 0U) { 56*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 57*b4734308SPeng Fan return; 58*b4734308SPeng Fan } 59*b4734308SPeng Fan 60*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 61*b4734308SPeng Fan } 62*b4734308SPeng Fan 63*b4734308SPeng Fan static void report_attributes(struct scmi_msg *msg) 64*b4734308SPeng Fan { 65*b4734308SPeng Fan struct scmi_protocol_attributes_p2a return_values = { 66*b4734308SPeng Fan .status = SCMI_SUCCESS, 67*b4734308SPeng Fan .attributes = plat_scmi_rstd_count(msg->agent_id), 68*b4734308SPeng Fan }; 69*b4734308SPeng Fan 70*b4734308SPeng Fan if (msg->in_size != 0U) { 71*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 72*b4734308SPeng Fan return; 73*b4734308SPeng Fan } 74*b4734308SPeng Fan 75*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 76*b4734308SPeng Fan } 77*b4734308SPeng Fan 78*b4734308SPeng Fan static void report_message_attributes(struct scmi_msg *msg) 79*b4734308SPeng Fan { 80*b4734308SPeng Fan struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in; 81*b4734308SPeng Fan struct scmi_protocol_message_attributes_p2a return_values = { 82*b4734308SPeng Fan .status = SCMI_SUCCESS, 83*b4734308SPeng Fan /* For this protocol, attributes shall be zero */ 84*b4734308SPeng Fan .attributes = 0U, 85*b4734308SPeng Fan }; 86*b4734308SPeng Fan 87*b4734308SPeng Fan if (msg->in_size != sizeof(*in_args)) { 88*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 89*b4734308SPeng Fan return; 90*b4734308SPeng Fan } 91*b4734308SPeng Fan 92*b4734308SPeng Fan if (!message_id_is_supported(in_args->message_id)) { 93*b4734308SPeng Fan scmi_status_response(msg, SCMI_NOT_FOUND); 94*b4734308SPeng Fan return; 95*b4734308SPeng Fan } 96*b4734308SPeng Fan 97*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 98*b4734308SPeng Fan } 99*b4734308SPeng Fan 100*b4734308SPeng Fan static void reset_domain_attributes(struct scmi_msg *msg) 101*b4734308SPeng Fan { 102*b4734308SPeng Fan struct scmi_reset_domain_attributes_a2p *in_args = (void *)msg->in; 103*b4734308SPeng Fan struct scmi_reset_domain_attributes_p2a return_values; 104*b4734308SPeng Fan const char *name = NULL; 105*b4734308SPeng Fan unsigned int domain_id = 0U; 106*b4734308SPeng Fan 107*b4734308SPeng Fan if (msg->in_size != sizeof(*in_args)) { 108*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 109*b4734308SPeng Fan return; 110*b4734308SPeng Fan } 111*b4734308SPeng Fan 112*b4734308SPeng Fan domain_id = SPECULATION_SAFE_VALUE(in_args->domain_id); 113*b4734308SPeng Fan 114*b4734308SPeng Fan if (domain_id >= plat_scmi_rstd_count(msg->agent_id)) { 115*b4734308SPeng Fan scmi_status_response(msg, SCMI_INVALID_PARAMETERS); 116*b4734308SPeng Fan return; 117*b4734308SPeng Fan } 118*b4734308SPeng Fan 119*b4734308SPeng Fan name = plat_scmi_rstd_get_name(msg->agent_id, domain_id); 120*b4734308SPeng Fan if (name == NULL) { 121*b4734308SPeng Fan scmi_status_response(msg, SCMI_NOT_FOUND); 122*b4734308SPeng Fan return; 123*b4734308SPeng Fan } 124*b4734308SPeng Fan 125*b4734308SPeng Fan zeromem(&return_values, sizeof(return_values)); 126*b4734308SPeng Fan COPY_NAME_IDENTIFIER(return_values.name, name); 127*b4734308SPeng Fan return_values.status = SCMI_SUCCESS; 128*b4734308SPeng Fan return_values.flags = 0U; /* Async and Notif are not supported */ 129*b4734308SPeng Fan return_values.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT; 130*b4734308SPeng Fan 131*b4734308SPeng Fan scmi_write_response(msg, &return_values, sizeof(return_values)); 132*b4734308SPeng Fan } 133*b4734308SPeng Fan 134*b4734308SPeng Fan static void reset_request(struct scmi_msg *msg) 135*b4734308SPeng Fan { 136*b4734308SPeng Fan struct scmi_reset_domain_request_a2p *in_args = (void *)msg->in; 137*b4734308SPeng Fan struct scmi_reset_domain_request_p2a out_args = { 138*b4734308SPeng Fan .status = SCMI_SUCCESS, 139*b4734308SPeng Fan }; 140*b4734308SPeng Fan unsigned int domain_id = 0U; 141*b4734308SPeng Fan 142*b4734308SPeng Fan if (msg->in_size != sizeof(*in_args)) { 143*b4734308SPeng Fan scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 144*b4734308SPeng Fan return; 145*b4734308SPeng Fan } 146*b4734308SPeng Fan 147*b4734308SPeng Fan domain_id = SPECULATION_SAFE_VALUE(in_args->domain_id); 148*b4734308SPeng Fan 149*b4734308SPeng Fan if (domain_id >= plat_scmi_rstd_count(msg->agent_id)) { 150*b4734308SPeng Fan scmi_status_response(msg, SCMI_NOT_FOUND); 151*b4734308SPeng Fan return; 152*b4734308SPeng Fan } 153*b4734308SPeng Fan 154*b4734308SPeng Fan if ((in_args->flags & SCMI_RESET_DOMAIN_AUTO) != 0U) { 155*b4734308SPeng Fan out_args.status = plat_scmi_rstd_autonomous(msg->agent_id, 156*b4734308SPeng Fan domain_id, 157*b4734308SPeng Fan in_args->reset_state); 158*b4734308SPeng Fan } else if ((in_args->flags & SCMI_RESET_DOMAIN_EXPLICIT) != 0U) { 159*b4734308SPeng Fan out_args.status = plat_scmi_rstd_set_state(msg->agent_id, 160*b4734308SPeng Fan domain_id, true); 161*b4734308SPeng Fan } else { 162*b4734308SPeng Fan out_args.status = plat_scmi_rstd_set_state(msg->agent_id, 163*b4734308SPeng Fan domain_id, false); 164*b4734308SPeng Fan } 165*b4734308SPeng Fan 166*b4734308SPeng Fan if (out_args.status != SCMI_SUCCESS) { 167*b4734308SPeng Fan scmi_status_response(msg, out_args.status); 168*b4734308SPeng Fan } else { 169*b4734308SPeng Fan scmi_write_response(msg, &out_args, sizeof(out_args)); 170*b4734308SPeng Fan } 171*b4734308SPeng Fan } 172*b4734308SPeng Fan 173*b4734308SPeng Fan static const scmi_msg_handler_t scmi_rstd_handler_table[] = { 174*b4734308SPeng Fan [SCMI_PROTOCOL_VERSION] = report_version, 175*b4734308SPeng Fan [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes, 176*b4734308SPeng Fan [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes, 177*b4734308SPeng Fan [SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_domain_attributes, 178*b4734308SPeng Fan [SCMI_RESET_DOMAIN_REQUEST] = reset_request, 179*b4734308SPeng Fan }; 180*b4734308SPeng Fan 181*b4734308SPeng Fan static bool message_id_is_supported(unsigned int message_id) 182*b4734308SPeng Fan { 183*b4734308SPeng Fan return (message_id < ARRAY_SIZE(scmi_rstd_handler_table)) && 184*b4734308SPeng Fan (scmi_rstd_handler_table[message_id] != NULL); 185*b4734308SPeng Fan } 186*b4734308SPeng Fan 187*b4734308SPeng Fan scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg) 188*b4734308SPeng Fan { 189*b4734308SPeng Fan unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id); 190*b4734308SPeng Fan 191*b4734308SPeng Fan if (message_id >= ARRAY_SIZE(scmi_rstd_handler_table)) { 192*b4734308SPeng Fan VERBOSE("Reset domain handle not found %u\n", msg->message_id); 193*b4734308SPeng Fan return NULL; 194*b4734308SPeng Fan } 195*b4734308SPeng Fan 196*b4734308SPeng Fan return scmi_rstd_handler_table[message_id]; 197*b4734308SPeng Fan } 198