1ae8c8068SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 2ae8c8068SEtienne Carriere /* 3ae8c8068SEtienne Carriere * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. 4*5c34a982SEtienne Carriere * Copyright (c) 2019-2022, Linaro Limited 5ae8c8068SEtienne Carriere */ 6*5c34a982SEtienne Carriere #include <assert.h> 7ae8c8068SEtienne Carriere #include <drivers/scmi-msg.h> 8ae8c8068SEtienne Carriere #include <drivers/scmi.h> 9*5c34a982SEtienne Carriere #include <kernel/spinlock.h> 10*5c34a982SEtienne Carriere #include <string.h> 11ae8c8068SEtienne Carriere #include <trace.h> 12ae8c8068SEtienne Carriere 1360c96f68SEtienne Carriere #include "base.h" 1460c96f68SEtienne Carriere #include "clock.h" 15ae8c8068SEtienne Carriere #include "common.h" 1660c96f68SEtienne Carriere #include "reset_domain.h" 1760c96f68SEtienne Carriere #include "voltage_domain.h" 18ae8c8068SEtienne Carriere 19*5c34a982SEtienne Carriere /* SMP protection on channel->busy field */ 20*5c34a982SEtienne Carriere static unsigned int smt_channels_lock; 21*5c34a982SEtienne Carriere 22*5c34a982SEtienne Carriere /* If channel is not busy, set busy and return true, otherwise return false */ 23*5c34a982SEtienne Carriere bool scmi_msg_claim_channel(struct scmi_msg_channel *channel) 24*5c34a982SEtienne Carriere { 25*5c34a982SEtienne Carriere uint32_t exceptions = cpu_spin_lock_xsave(&smt_channels_lock); 26*5c34a982SEtienne Carriere bool channel_is_busy = channel->busy; 27*5c34a982SEtienne Carriere 28*5c34a982SEtienne Carriere if (!channel_is_busy) 29*5c34a982SEtienne Carriere channel->busy = true; 30*5c34a982SEtienne Carriere 31*5c34a982SEtienne Carriere cpu_spin_unlock_xrestore(&smt_channels_lock, exceptions); 32*5c34a982SEtienne Carriere 33*5c34a982SEtienne Carriere return !channel_is_busy; 34*5c34a982SEtienne Carriere } 35*5c34a982SEtienne Carriere 36*5c34a982SEtienne Carriere void scmi_msg_release_channel(struct scmi_msg_channel *channel) 37*5c34a982SEtienne Carriere { 38*5c34a982SEtienne Carriere channel->busy = false; 39*5c34a982SEtienne Carriere } 40*5c34a982SEtienne Carriere 41ae8c8068SEtienne Carriere void scmi_status_response(struct scmi_msg *msg, int32_t status) 42ae8c8068SEtienne Carriere { 43ae8c8068SEtienne Carriere assert(msg->out && msg->out_size >= sizeof(int32_t)); 44ae8c8068SEtienne Carriere 45ae8c8068SEtienne Carriere memcpy(msg->out, &status, sizeof(int32_t)); 46ae8c8068SEtienne Carriere msg->out_size_out = sizeof(int32_t); 47ae8c8068SEtienne Carriere } 48ae8c8068SEtienne Carriere 49ae8c8068SEtienne Carriere void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size) 50ae8c8068SEtienne Carriere { 51ae8c8068SEtienne Carriere /* 52ae8c8068SEtienne Carriere * Output payload shall be at least the size of the status 53ae8c8068SEtienne Carriere * Output buffer shall be at least be the size of the status 54ae8c8068SEtienne Carriere * Output paylaod shall fit in output buffer 55ae8c8068SEtienne Carriere */ 56ae8c8068SEtienne Carriere assert(payload && size >= sizeof(int32_t) && size <= msg->out_size && 57ae8c8068SEtienne Carriere msg->out && msg->out_size >= sizeof(int32_t)); 58ae8c8068SEtienne Carriere 59ae8c8068SEtienne Carriere memcpy(msg->out, payload, size); 60ae8c8068SEtienne Carriere msg->out_size_out = size; 61ae8c8068SEtienne Carriere } 62ae8c8068SEtienne Carriere 63ae8c8068SEtienne Carriere void scmi_process_message(struct scmi_msg *msg) 64ae8c8068SEtienne Carriere { 65ae8c8068SEtienne Carriere scmi_msg_handler_t handler = NULL; 66ae8c8068SEtienne Carriere 67ae8c8068SEtienne Carriere switch (msg->protocol_id) { 68ae8c8068SEtienne Carriere case SCMI_PROTOCOL_ID_BASE: 69ae8c8068SEtienne Carriere handler = scmi_msg_get_base_handler(msg); 70ae8c8068SEtienne Carriere break; 71a7a9e3baSEtienne Carriere case SCMI_PROTOCOL_ID_CLOCK: 72a7a9e3baSEtienne Carriere handler = scmi_msg_get_clock_handler(msg); 73a7a9e3baSEtienne Carriere break; 7456a1f10eSEtienne Carriere case SCMI_PROTOCOL_ID_RESET_DOMAIN: 7556a1f10eSEtienne Carriere handler = scmi_msg_get_rd_handler(msg); 7656a1f10eSEtienne Carriere break; 77006d89b8SEtienne Carriere case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: 78006d89b8SEtienne Carriere handler = scmi_msg_get_voltd_handler(msg); 79006d89b8SEtienne Carriere break; 80ae8c8068SEtienne Carriere default: 81ae8c8068SEtienne Carriere break; 82ae8c8068SEtienne Carriere } 83ae8c8068SEtienne Carriere 84ae8c8068SEtienne Carriere if (handler) { 85ae8c8068SEtienne Carriere handler(msg); 86ae8c8068SEtienne Carriere return; 87ae8c8068SEtienne Carriere } 88ae8c8068SEtienne Carriere 89659a1f88SEtienne Carriere DMSG("Channel %u Protocol %#x Message %#x: not supported", 90659a1f88SEtienne Carriere msg->channel_id, msg->protocol_id, msg->message_id); 91ae8c8068SEtienne Carriere 92ae8c8068SEtienne Carriere scmi_status_response(msg, SCMI_NOT_SUPPORTED); 93ae8c8068SEtienne Carriere } 94