1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. 4 * Copyright (c) 2019-2020, Linaro Limited 5 */ 6 #include <cdefs.h> 7 #include <string.h> 8 9 #include <drivers/scmi-msg.h> 10 #include <drivers/scmi.h> 11 #include <lib/utils_def.h> 12 13 #include "common.h" 14 15 #pragma weak plat_scmi_pd_count 16 #pragma weak plat_scmi_pd_get_name 17 #pragma weak plat_scmi_pd_get_state 18 #pragma weak plat_scmi_pd_set_state 19 #pragma weak plat_scmi_pd_statistics 20 #pragma weak plat_scmi_pd_get_attributes 21 22 static bool message_id_is_supported(unsigned int message_id); 23 24 size_t plat_scmi_pd_count(unsigned int agent_id __unused) 25 { 26 return 0U; 27 } 28 29 const char *plat_scmi_pd_get_name(unsigned int agent_id __unused, 30 unsigned int pd_id __unused) 31 { 32 return NULL; 33 } 34 35 unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused, 36 unsigned long *pd_id __unused) 37 { 38 return 0U; 39 } 40 41 unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused, 42 unsigned int pd_id __unused) 43 { 44 return 0U; 45 } 46 47 unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused, 48 unsigned int pd_id __unused) 49 { 50 return 0U; 51 } 52 53 int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused, 54 unsigned int flags __unused, 55 unsigned int pd_id __unused, 56 unsigned int state __unused) 57 { 58 return SCMI_NOT_SUPPORTED; 59 } 60 61 static void report_version(struct scmi_msg *msg) 62 { 63 struct scmi_protocol_version_p2a return_values = { 64 .status = SCMI_SUCCESS, 65 .version = SCMI_PROTOCOL_VERSION_PD, 66 }; 67 68 if (msg->in_size != 0) { 69 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 70 return; 71 } 72 73 scmi_write_response(msg, &return_values, sizeof(return_values)); 74 } 75 76 static void report_attributes(struct scmi_msg *msg) 77 { 78 unsigned long addr = 0UL; 79 unsigned int len; 80 81 struct scmi_protocol_attributes_p2a_pd return_values = { 82 .status = SCMI_SUCCESS, 83 }; 84 85 if (msg->in_size != 0) { 86 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 87 return; 88 } 89 90 return_values.attributes = plat_scmi_pd_count(msg->agent_id); 91 len = plat_scmi_pd_statistics(msg->agent_id, &addr); 92 if (len != 0U) { 93 return_values.statistics_addr_low = (unsigned int)addr; 94 return_values.statistics_addr_high = (uint32_t)(addr >> 32); 95 return_values.statistics_len = len; 96 } 97 98 scmi_write_response(msg, &return_values, sizeof(return_values)); 99 } 100 101 static void report_message_attributes(struct scmi_msg *msg) 102 { 103 struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in; 104 struct scmi_protocol_message_attributes_p2a return_values = { 105 .status = SCMI_SUCCESS, 106 /* For this protocol, attributes shall be zero */ 107 .attributes = 0U, 108 }; 109 110 if (msg->in_size != sizeof(*in_args)) { 111 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 112 return; 113 } 114 115 if (!message_id_is_supported(in_args->message_id)) { 116 scmi_status_response(msg, SCMI_NOT_FOUND); 117 return; 118 } 119 120 scmi_write_response(msg, &return_values, sizeof(return_values)); 121 } 122 123 static void scmi_pd_attributes(struct scmi_msg *msg) 124 { 125 const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in; 126 struct scmi_pd_attributes_p2a return_values = { 127 .status = SCMI_SUCCESS, 128 }; 129 const char *name = NULL; 130 unsigned int pd_id = 0U; 131 132 if (msg->in_size != sizeof(*in_args)) { 133 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 134 return; 135 } 136 137 pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); 138 139 if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { 140 scmi_status_response(msg, SCMI_NOT_FOUND); 141 return; 142 } 143 144 name = plat_scmi_pd_get_name(msg->agent_id, pd_id); 145 if (name == NULL) { 146 scmi_status_response(msg, SCMI_NOT_FOUND); 147 return; 148 } 149 150 COPY_NAME_IDENTIFIER(return_values.pd_name, name); 151 152 return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id); 153 154 scmi_write_response(msg, &return_values, sizeof(return_values)); 155 } 156 157 static void scmi_pd_state_get(struct scmi_msg *msg) 158 { 159 const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in; 160 unsigned int state = 0U; 161 struct scmi_pd_state_get_p2a return_values = { 162 .status = SCMI_SUCCESS, 163 }; 164 unsigned int pd_id = 0U; 165 166 if (msg->in_size != sizeof(*in_args)) { 167 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 168 return; 169 } 170 171 pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); 172 173 if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { 174 scmi_status_response(msg, SCMI_NOT_FOUND); 175 return; 176 } 177 178 state = plat_scmi_pd_get_state(msg->agent_id, pd_id); 179 180 return_values.power_state = state; 181 182 scmi_write_response(msg, &return_values, sizeof(return_values)); 183 } 184 185 static void scmi_pd_state_set(struct scmi_msg *msg) 186 { 187 const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in; 188 unsigned int flags = 0U; 189 int32_t status = 0; 190 unsigned int pd_id = 0U; 191 unsigned int state = 0U; 192 193 if (msg->in_size != sizeof(*in_args)) { 194 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 195 return; 196 } 197 198 pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); 199 200 if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { 201 scmi_status_response(msg, SCMI_NOT_FOUND); 202 return; 203 } 204 205 flags = SPECULATION_SAFE_VALUE(in_args->flags); 206 state = SPECULATION_SAFE_VALUE(in_args->power_state); 207 208 status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state); 209 210 scmi_status_response(msg, status); 211 } 212 213 static const scmi_msg_handler_t scmi_pd_handler_table[] = { 214 [SCMI_PROTOCOL_VERSION] = report_version, 215 [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes, 216 [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes, 217 [SCMI_PD_ATTRIBUTES] = scmi_pd_attributes, 218 [SCMI_PD_STATE_SET] = scmi_pd_state_set, 219 [SCMI_PD_STATE_GET] = scmi_pd_state_get, 220 }; 221 222 static bool message_id_is_supported(unsigned int message_id) 223 { 224 return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) && 225 (scmi_pd_handler_table[message_id] != NULL); 226 } 227 228 scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg) 229 { 230 const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table); 231 unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id); 232 233 if (message_id >= array_size) { 234 VERBOSE("pd handle not found %u", msg->message_id); 235 return NULL; 236 } 237 238 return scmi_pd_handler_table[message_id]; 239 } 240