156a1f10eSEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
256a1f10eSEtienne Carriere /*
356a1f10eSEtienne Carriere * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
456a1f10eSEtienne Carriere * Copyright (c) 2019, Linaro Limited
556a1f10eSEtienne Carriere */
656a1f10eSEtienne Carriere #include <assert.h>
756a1f10eSEtienne Carriere #include <confine_array_index.h>
856a1f10eSEtienne Carriere #include <drivers/scmi-msg.h>
956a1f10eSEtienne Carriere #include <drivers/scmi.h>
1056a1f10eSEtienne Carriere #include <string.h>
1156a1f10eSEtienne Carriere #include <util.h>
1256a1f10eSEtienne Carriere
1356a1f10eSEtienne Carriere #include "common.h"
1460c96f68SEtienne Carriere #include "reset_domain.h"
1556a1f10eSEtienne Carriere
1656a1f10eSEtienne Carriere static bool message_id_is_supported(unsigned int message_id);
1756a1f10eSEtienne Carriere
plat_scmi_rd_count(unsigned int channel_id __unused)18*659a1f88SEtienne Carriere size_t __weak plat_scmi_rd_count(unsigned int channel_id __unused)
1956a1f10eSEtienne Carriere {
2056a1f10eSEtienne Carriere return 0;
2156a1f10eSEtienne Carriere }
2256a1f10eSEtienne Carriere
plat_scmi_rd_get_name(unsigned int channel_id __unused,unsigned int scmi_id __unused)23*659a1f88SEtienne Carriere const char __weak *plat_scmi_rd_get_name(unsigned int channel_id __unused,
2456a1f10eSEtienne Carriere unsigned int scmi_id __unused)
2556a1f10eSEtienne Carriere {
2656a1f10eSEtienne Carriere return NULL;
2756a1f10eSEtienne Carriere }
2856a1f10eSEtienne Carriere
plat_scmi_rd_autonomous(unsigned int channel_id __unused,unsigned int scmi_id __unused,unsigned int state __unused)29*659a1f88SEtienne Carriere int32_t __weak plat_scmi_rd_autonomous(unsigned int channel_id __unused,
3056a1f10eSEtienne Carriere unsigned int scmi_id __unused,
3156a1f10eSEtienne Carriere unsigned int state __unused)
3256a1f10eSEtienne Carriere {
3356a1f10eSEtienne Carriere return SCMI_NOT_SUPPORTED;
3456a1f10eSEtienne Carriere }
3556a1f10eSEtienne Carriere
plat_scmi_rd_set_state(unsigned int channel_id __unused,unsigned int scmi_id __unused,bool assert_not_deassert __unused)36*659a1f88SEtienne Carriere int32_t __weak plat_scmi_rd_set_state(unsigned int channel_id __unused,
3756a1f10eSEtienne Carriere unsigned int scmi_id __unused,
3856a1f10eSEtienne Carriere bool assert_not_deassert __unused)
3956a1f10eSEtienne Carriere {
4056a1f10eSEtienne Carriere return SCMI_NOT_SUPPORTED;
4156a1f10eSEtienne Carriere }
4256a1f10eSEtienne Carriere
report_version(struct scmi_msg * msg)4356a1f10eSEtienne Carriere static void report_version(struct scmi_msg *msg)
4456a1f10eSEtienne Carriere {
4556a1f10eSEtienne Carriere struct scmi_protocol_version_p2a return_values = {
4656a1f10eSEtienne Carriere .status = SCMI_SUCCESS,
4756a1f10eSEtienne Carriere .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
4856a1f10eSEtienne Carriere };
4956a1f10eSEtienne Carriere
5056a1f10eSEtienne Carriere if (msg->in_size) {
5156a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
5256a1f10eSEtienne Carriere return;
5356a1f10eSEtienne Carriere }
5456a1f10eSEtienne Carriere
5556a1f10eSEtienne Carriere scmi_write_response(msg, &return_values, sizeof(return_values));
5656a1f10eSEtienne Carriere }
5756a1f10eSEtienne Carriere
report_attributes(struct scmi_msg * msg)5856a1f10eSEtienne Carriere static void report_attributes(struct scmi_msg *msg)
5956a1f10eSEtienne Carriere {
6056a1f10eSEtienne Carriere struct scmi_protocol_attributes_p2a return_values = {
6156a1f10eSEtienne Carriere .status = SCMI_SUCCESS,
62*659a1f88SEtienne Carriere .attributes = plat_scmi_rd_count(msg->channel_id),
6356a1f10eSEtienne Carriere };
6456a1f10eSEtienne Carriere
6556a1f10eSEtienne Carriere if (msg->in_size) {
6656a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
6756a1f10eSEtienne Carriere return;
6856a1f10eSEtienne Carriere }
6956a1f10eSEtienne Carriere
7056a1f10eSEtienne Carriere scmi_write_response(msg, &return_values, sizeof(return_values));
7156a1f10eSEtienne Carriere }
7256a1f10eSEtienne Carriere
report_message_attributes(struct scmi_msg * msg)7356a1f10eSEtienne Carriere static void report_message_attributes(struct scmi_msg *msg)
7456a1f10eSEtienne Carriere {
7556a1f10eSEtienne Carriere struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
7656a1f10eSEtienne Carriere struct scmi_protocol_message_attributes_p2a return_values = {
7756a1f10eSEtienne Carriere .status = SCMI_SUCCESS,
7856a1f10eSEtienne Carriere /* For this protocol, attributes shall be zero */
7956a1f10eSEtienne Carriere .attributes = 0,
8056a1f10eSEtienne Carriere };
8156a1f10eSEtienne Carriere
8256a1f10eSEtienne Carriere if (msg->in_size != sizeof(*in_args)) {
8356a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
8456a1f10eSEtienne Carriere return;
8556a1f10eSEtienne Carriere }
8656a1f10eSEtienne Carriere
8756a1f10eSEtienne Carriere if (!message_id_is_supported(in_args->message_id)) {
8856a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_NOT_FOUND);
8956a1f10eSEtienne Carriere return;
9056a1f10eSEtienne Carriere }
9156a1f10eSEtienne Carriere
9256a1f10eSEtienne Carriere scmi_write_response(msg, &return_values, sizeof(return_values));
9356a1f10eSEtienne Carriere }
9456a1f10eSEtienne Carriere
reset_domain_attributes(struct scmi_msg * msg)9556a1f10eSEtienne Carriere static void reset_domain_attributes(struct scmi_msg *msg)
9656a1f10eSEtienne Carriere {
9756a1f10eSEtienne Carriere struct scmi_reset_domain_attributes_a2p *in_args = (void *)msg->in;
9856a1f10eSEtienne Carriere struct scmi_reset_domain_attributes_p2a return_values = { };
9956a1f10eSEtienne Carriere const char *name = NULL;
10056a1f10eSEtienne Carriere unsigned int domain_id = 0;
10156a1f10eSEtienne Carriere
10256a1f10eSEtienne Carriere if (msg->in_size != sizeof(*in_args)) {
10356a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
10456a1f10eSEtienne Carriere return;
10556a1f10eSEtienne Carriere }
10656a1f10eSEtienne Carriere
107*659a1f88SEtienne Carriere if (in_args->domain_id >= plat_scmi_rd_count(msg->channel_id)) {
10856a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
10956a1f10eSEtienne Carriere return;
11056a1f10eSEtienne Carriere }
11156a1f10eSEtienne Carriere
11256a1f10eSEtienne Carriere domain_id = confine_array_index(in_args->domain_id,
113*659a1f88SEtienne Carriere plat_scmi_rd_count(msg->channel_id));
11456a1f10eSEtienne Carriere
115*659a1f88SEtienne Carriere name = plat_scmi_rd_get_name(msg->channel_id, domain_id);
11656a1f10eSEtienne Carriere if (!name) {
11756a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_NOT_FOUND);
11856a1f10eSEtienne Carriere return;
11956a1f10eSEtienne Carriere }
12056a1f10eSEtienne Carriere
12156a1f10eSEtienne Carriere COPY_NAME_IDENTIFIER(return_values.name, name);
12256a1f10eSEtienne Carriere return_values.status = SCMI_SUCCESS;
12356a1f10eSEtienne Carriere return_values.flags = 0; /* Async and Notif are not supported */
12456a1f10eSEtienne Carriere return_values.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT;
12556a1f10eSEtienne Carriere
12656a1f10eSEtienne Carriere scmi_write_response(msg, &return_values, sizeof(return_values));
12756a1f10eSEtienne Carriere }
12856a1f10eSEtienne Carriere
reset_request(struct scmi_msg * msg)12956a1f10eSEtienne Carriere static void reset_request(struct scmi_msg *msg)
13056a1f10eSEtienne Carriere {
13156a1f10eSEtienne Carriere struct scmi_reset_domain_request_a2p *in_args = (void *)msg->in;
13256a1f10eSEtienne Carriere struct scmi_reset_domain_request_p2a out_args = {
13356a1f10eSEtienne Carriere .status = SCMI_SUCCESS,
13456a1f10eSEtienne Carriere };
13556a1f10eSEtienne Carriere unsigned int domain_id = 0;
13656a1f10eSEtienne Carriere
13756a1f10eSEtienne Carriere domain_id = confine_array_index(in_args->domain_id,
138*659a1f88SEtienne Carriere plat_scmi_rd_count(msg->channel_id));
13956a1f10eSEtienne Carriere
14056a1f10eSEtienne Carriere if (msg->in_size != sizeof(*in_args)) {
14156a1f10eSEtienne Carriere scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
14256a1f10eSEtienne Carriere return;
14356a1f10eSEtienne Carriere }
14456a1f10eSEtienne Carriere
145*659a1f88SEtienne Carriere if (in_args->domain_id >= plat_scmi_rd_count(msg->channel_id)) {
146bef69837SEtienne Carriere scmi_status_response(msg, SCMI_NOT_FOUND);
14756a1f10eSEtienne Carriere return;
14856a1f10eSEtienne Carriere }
14956a1f10eSEtienne Carriere
15056a1f10eSEtienne Carriere if (in_args->flags & SCMI_RESET_DOMAIN_AUTO)
151*659a1f88SEtienne Carriere out_args.status = plat_scmi_rd_autonomous(msg->channel_id,
15256a1f10eSEtienne Carriere domain_id,
15356a1f10eSEtienne Carriere in_args->reset_state);
15456a1f10eSEtienne Carriere else if (in_args->flags & SCMI_RESET_DOMAIN_EXPLICIT)
155*659a1f88SEtienne Carriere out_args.status = plat_scmi_rd_set_state(msg->channel_id,
15656a1f10eSEtienne Carriere domain_id, true);
15756a1f10eSEtienne Carriere else
158*659a1f88SEtienne Carriere out_args.status = plat_scmi_rd_set_state(msg->channel_id,
15956a1f10eSEtienne Carriere domain_id, false);
16056a1f10eSEtienne Carriere
16156a1f10eSEtienne Carriere if (out_args.status)
16256a1f10eSEtienne Carriere scmi_status_response(msg, out_args.status);
16356a1f10eSEtienne Carriere else
16456a1f10eSEtienne Carriere scmi_write_response(msg, &out_args, sizeof(out_args));
16556a1f10eSEtienne Carriere }
16656a1f10eSEtienne Carriere
16756a1f10eSEtienne Carriere static const scmi_msg_handler_t scmi_rd_handler_table[] = {
16856a1f10eSEtienne Carriere [SCMI_PROTOCOL_VERSION] = report_version,
16956a1f10eSEtienne Carriere [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
17056a1f10eSEtienne Carriere [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
17156a1f10eSEtienne Carriere [SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_domain_attributes,
17256a1f10eSEtienne Carriere [SCMI_RESET_DOMAIN_REQUEST] = reset_request,
17356a1f10eSEtienne Carriere };
17456a1f10eSEtienne Carriere
message_id_is_supported(unsigned int message_id)17556a1f10eSEtienne Carriere static bool message_id_is_supported(unsigned int message_id)
17656a1f10eSEtienne Carriere {
17756a1f10eSEtienne Carriere return message_id < ARRAY_SIZE(scmi_rd_handler_table) &&
17856a1f10eSEtienne Carriere scmi_rd_handler_table[message_id];
17956a1f10eSEtienne Carriere }
18056a1f10eSEtienne Carriere
scmi_msg_get_rd_handler(struct scmi_msg * msg)18156a1f10eSEtienne Carriere scmi_msg_handler_t scmi_msg_get_rd_handler(struct scmi_msg *msg)
18256a1f10eSEtienne Carriere {
18356a1f10eSEtienne Carriere const size_t array_size = ARRAY_SIZE(scmi_rd_handler_table);
18456a1f10eSEtienne Carriere unsigned int message_id = 0;
18556a1f10eSEtienne Carriere
18656a1f10eSEtienne Carriere if (msg->message_id >= array_size) {
18756a1f10eSEtienne Carriere DMSG("Reset domain handle not found %u", msg->message_id);
18856a1f10eSEtienne Carriere return NULL;
18956a1f10eSEtienne Carriere }
19056a1f10eSEtienne Carriere
19156a1f10eSEtienne Carriere message_id = confine_array_index(msg->message_id, array_size);
19256a1f10eSEtienne Carriere
19356a1f10eSEtienne Carriere return scmi_rd_handler_table[message_id];
19456a1f10eSEtienne Carriere }
195