1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. 4 * Copyright (c) 2019-2022, Linaro Limited 5 */ 6 #include <assert.h> 7 #include <drivers/scmi-msg.h> 8 #include <drivers/scmi.h> 9 #include <kernel/spinlock.h> 10 #include <string.h> 11 #include <trace.h> 12 13 #include "base.h" 14 #include "clock.h" 15 #include "common.h" 16 #include "reset_domain.h" 17 #include "voltage_domain.h" 18 19 /* SMP protection on channel->busy field */ 20 static unsigned int smt_channels_lock; 21 22 /* If channel is not busy, set busy and return true, otherwise return false */ 23 bool scmi_msg_claim_channel(struct scmi_msg_channel *channel) 24 { 25 uint32_t exceptions = cpu_spin_lock_xsave(&smt_channels_lock); 26 bool channel_is_busy = channel->busy; 27 28 if (!channel_is_busy) 29 channel->busy = true; 30 31 cpu_spin_unlock_xrestore(&smt_channels_lock, exceptions); 32 33 return !channel_is_busy; 34 } 35 36 void scmi_msg_release_channel(struct scmi_msg_channel *channel) 37 { 38 channel->busy = false; 39 } 40 41 void scmi_status_response(struct scmi_msg *msg, int32_t status) 42 { 43 assert(msg->out && msg->out_size >= sizeof(int32_t)); 44 45 memcpy(msg->out, &status, sizeof(int32_t)); 46 msg->out_size_out = sizeof(int32_t); 47 } 48 49 void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size) 50 { 51 if (msg->out_size < size) { 52 DMSG("SCMI resp. payload %zu > %zu bytes", size, msg->out_size); 53 scmi_status_response(msg, SCMI_PROTOCOL_ERROR); 54 } else { 55 memcpy(msg->out, payload, size); 56 msg->out_size_out = size; 57 } 58 } 59 60 void scmi_process_message(struct scmi_msg *msg) 61 { 62 scmi_msg_handler_t handler = NULL; 63 64 switch (msg->protocol_id) { 65 case SCMI_PROTOCOL_ID_BASE: 66 handler = scmi_msg_get_base_handler(msg); 67 break; 68 case SCMI_PROTOCOL_ID_CLOCK: 69 handler = scmi_msg_get_clock_handler(msg); 70 break; 71 case SCMI_PROTOCOL_ID_RESET_DOMAIN: 72 handler = scmi_msg_get_rd_handler(msg); 73 break; 74 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: 75 handler = scmi_msg_get_voltd_handler(msg); 76 break; 77 default: 78 break; 79 } 80 81 if (handler) { 82 handler(msg); 83 return; 84 } 85 86 DMSG("Channel %u Protocol %#x Message %#x: not supported", 87 msg->channel_id, msg->protocol_id, msg->message_id); 88 89 scmi_status_response(msg, SCMI_NOT_SUPPORTED); 90 } 91