xref: /optee_os/core/drivers/scmi-msg/entry.c (revision 7b49ff335a105e2dfa357c9fbc775904ac9adc97)
1ae8c8068SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
2ae8c8068SEtienne Carriere /*
3ae8c8068SEtienne Carriere  * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
45c34a982SEtienne Carriere  * Copyright (c) 2019-2022, Linaro Limited
5ae8c8068SEtienne Carriere  */
65c34a982SEtienne Carriere #include <assert.h>
7ae8c8068SEtienne Carriere #include <drivers/scmi-msg.h>
8ae8c8068SEtienne Carriere #include <drivers/scmi.h>
95c34a982SEtienne Carriere #include <kernel/spinlock.h>
105c34a982SEtienne 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 
195c34a982SEtienne Carriere /* SMP protection on channel->busy field */
205c34a982SEtienne Carriere static unsigned int smt_channels_lock;
215c34a982SEtienne Carriere 
225c34a982SEtienne Carriere /* If channel is not busy, set busy and return true, otherwise return false */
235c34a982SEtienne Carriere bool scmi_msg_claim_channel(struct scmi_msg_channel *channel)
245c34a982SEtienne Carriere {
255c34a982SEtienne Carriere 	uint32_t exceptions = cpu_spin_lock_xsave(&smt_channels_lock);
265c34a982SEtienne Carriere 	bool channel_is_busy = channel->busy;
275c34a982SEtienne Carriere 
285c34a982SEtienne Carriere 	if (!channel_is_busy)
295c34a982SEtienne Carriere 		channel->busy = true;
305c34a982SEtienne Carriere 
315c34a982SEtienne Carriere 	cpu_spin_unlock_xrestore(&smt_channels_lock, exceptions);
325c34a982SEtienne Carriere 
335c34a982SEtienne Carriere 	return !channel_is_busy;
345c34a982SEtienne Carriere }
355c34a982SEtienne Carriere 
365c34a982SEtienne Carriere void scmi_msg_release_channel(struct scmi_msg_channel *channel)
375c34a982SEtienne Carriere {
385c34a982SEtienne Carriere 	channel->busy = false;
395c34a982SEtienne Carriere }
405c34a982SEtienne 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 {
51*7b49ff33SEtienne Carriere 	if (msg->out_size < size) {
52*7b49ff33SEtienne Carriere 		DMSG("SCMI resp. payload %zu > %zu bytes", size, msg->out_size);
53*7b49ff33SEtienne Carriere 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
54*7b49ff33SEtienne Carriere 	} else {
55ae8c8068SEtienne Carriere 		memcpy(msg->out, payload, size);
56ae8c8068SEtienne Carriere 		msg->out_size_out = size;
57ae8c8068SEtienne Carriere 	}
58*7b49ff33SEtienne Carriere }
59ae8c8068SEtienne Carriere 
60ae8c8068SEtienne Carriere void scmi_process_message(struct scmi_msg *msg)
61ae8c8068SEtienne Carriere {
62ae8c8068SEtienne Carriere 	scmi_msg_handler_t handler = NULL;
63ae8c8068SEtienne Carriere 
64ae8c8068SEtienne Carriere 	switch (msg->protocol_id) {
65ae8c8068SEtienne Carriere 	case SCMI_PROTOCOL_ID_BASE:
66ae8c8068SEtienne Carriere 		handler = scmi_msg_get_base_handler(msg);
67ae8c8068SEtienne Carriere 		break;
68a7a9e3baSEtienne Carriere 	case SCMI_PROTOCOL_ID_CLOCK:
69a7a9e3baSEtienne Carriere 		handler = scmi_msg_get_clock_handler(msg);
70a7a9e3baSEtienne Carriere 		break;
7156a1f10eSEtienne Carriere 	case SCMI_PROTOCOL_ID_RESET_DOMAIN:
7256a1f10eSEtienne Carriere 		handler = scmi_msg_get_rd_handler(msg);
7356a1f10eSEtienne Carriere 		break;
74006d89b8SEtienne Carriere 	case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
75006d89b8SEtienne Carriere 		handler = scmi_msg_get_voltd_handler(msg);
76006d89b8SEtienne Carriere 		break;
77ae8c8068SEtienne Carriere 	default:
78ae8c8068SEtienne Carriere 		break;
79ae8c8068SEtienne Carriere 	}
80ae8c8068SEtienne Carriere 
81ae8c8068SEtienne Carriere 	if (handler) {
82ae8c8068SEtienne Carriere 		handler(msg);
83ae8c8068SEtienne Carriere 		return;
84ae8c8068SEtienne Carriere 	}
85ae8c8068SEtienne Carriere 
86659a1f88SEtienne Carriere 	DMSG("Channel %u Protocol %#x Message %#x: not supported",
87659a1f88SEtienne Carriere 	     msg->channel_id, msg->protocol_id, msg->message_id);
88ae8c8068SEtienne Carriere 
89ae8c8068SEtienne Carriere 	scmi_status_response(msg, SCMI_NOT_SUPPORTED);
90ae8c8068SEtienne Carriere }
91