xref: /optee_os/core/drivers/scmi-msg/entry.c (revision 5c34a982f7e3cc1b802c20a166d892b8f5d35f18)
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