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