1 /*
2  * Copyright 2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief SCMI Common Protocol Commands Implementation
10  *
11  * This file contains the implementation of the SCMI commands that are
12  * common to all protocols (generic or vendor-specific) as listed in
13  * ARM SCMI Specification such as v4.0 (DEN0056F), Section 3.2.2 "Base protocol Commands".
14  *
15  * The following common commands are implemented:
16  * - PROTOCOL_VERSION (0x0): Query protocol version
17  * - PROTOCOL_ATTRIBUTES (0x1): Get protocol-specific attributes
18  * - MESSAGE_ATTRIBUTES (0x2): Query message capabilities
19  * - NEGOTIATE_PROTOCOL_VERSION (0x10): Negotiate protocol version support
20  *
21  * These commands provide standardized interfaces that can be reused across
22  * different SCMI protocol implementations, ensuring consistency and reducing
23  * code duplication.
24  *
25  * Reference: ARM System Control and Management Interface Platform Design Document
26  * Version 4.0, Document number: DEN0056F
27  * Available at: https://developer.arm.com/documentation/den0056/latest
28  */
29 
30 #include <string.h>
31 #include <zephyr/kernel.h>
32 #include <zephyr/drivers/firmware/scmi/protocol.h>
33 
34 struct scmi_protocol_version_reply {
35 	int32_t status;
36 	uint32_t version;
37 };
38 
39 struct scmi_protocol_attributes_reply {
40 	int32_t status;
41 	uint32_t attributes;
42 };
43 
44 struct scmi_protocol_message_attributes_reply {
45 	int32_t status;
46 	uint32_t attributes;
47 };
48 
scmi_protocol_get_version(struct scmi_protocol * proto,uint32_t * version)49 int scmi_protocol_get_version(struct scmi_protocol *proto, uint32_t *version)
50 {
51 	struct scmi_protocol_version_reply reply_buffer;
52 	struct scmi_message msg, reply;
53 	int ret;
54 
55 	if (!proto || !version) {
56 		return -EINVAL;
57 	}
58 
59 	msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_MSG_PROTOCOL_VERSION, SCMI_COMMAND,
60 			proto->id, 0x0);
61 	msg.len = 0;
62 	msg.content = NULL;
63 
64 	reply.hdr = msg.hdr;
65 	reply.len = sizeof(reply_buffer);
66 	reply.content = &reply_buffer;
67 
68 	ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel());
69 	if (ret < 0) {
70 		return ret;
71 	}
72 
73 	*version = reply_buffer.version;
74 
75 	return scmi_status_to_errno(reply_buffer.status);
76 }
77 
scmi_protocol_attributes_get(struct scmi_protocol * proto,uint32_t * attributes)78 int scmi_protocol_attributes_get(struct scmi_protocol *proto, uint32_t *attributes)
79 {
80 	struct scmi_protocol_attributes_reply reply_buffer;
81 	struct scmi_message msg, reply;
82 	int ret;
83 
84 	if (!proto || !attributes) {
85 		return -EINVAL;
86 	}
87 
88 	msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_MSG_PROTOCOL_ATTRIBUTES, SCMI_COMMAND,
89 			proto->id, 0x0);
90 	msg.len = 0;
91 	msg.content = NULL;
92 
93 	reply.hdr = msg.hdr;
94 	reply.len = sizeof(reply_buffer);
95 	reply.content = &reply_buffer;
96 
97 	ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel());
98 	if (ret < 0) {
99 		return ret;
100 	}
101 
102 	*attributes = reply_buffer.attributes;
103 
104 	return scmi_status_to_errno(reply_buffer.status);
105 }
106 
scmi_protocol_message_attributes_get(struct scmi_protocol * proto,uint32_t message_id,uint32_t * attributes)107 int scmi_protocol_message_attributes_get(struct scmi_protocol *proto,
108 					uint32_t message_id, uint32_t *attributes)
109 {
110 	struct scmi_protocol_message_attributes_reply reply_buffer;
111 	struct scmi_message msg, reply;
112 	int ret;
113 
114 	if (!proto || !attributes) {
115 		return -EINVAL;
116 	}
117 
118 	msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_MSG_MESSAGE_ATTRIBUTES, SCMI_COMMAND,
119 			proto->id, 0x0);
120 	msg.len = sizeof(message_id);
121 	msg.content = &message_id;
122 
123 	reply.hdr = msg.hdr;
124 	reply.len = sizeof(reply_buffer);
125 	reply.content = &reply_buffer;
126 
127 	ret = scmi_send_message(proto, &msg, &reply, true);
128 	if (ret < 0) {
129 		return ret;
130 	}
131 
132 	*attributes = reply_buffer.attributes;
133 
134 	return scmi_status_to_errno(reply_buffer.status);
135 }
136 
scmi_protocol_version_negotiate(struct scmi_protocol * proto,uint32_t version)137 int scmi_protocol_version_negotiate(struct scmi_protocol *proto, uint32_t version)
138 {
139 	struct scmi_message msg, reply;
140 	int32_t status;
141 	int ret;
142 
143 	if (!proto) {
144 		return -EINVAL;
145 	}
146 
147 	msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_MSG_NEGOTIATE_PROTOCOL_VERSION, SCMI_COMMAND,
148 			proto->id, 0x0);
149 	msg.len = sizeof(version);
150 	msg.content = &version;
151 
152 	reply.hdr = msg.hdr;
153 	reply.len = sizeof(status);
154 	reply.content = &status;
155 
156 	ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel());
157 	if (ret < 0) {
158 		return ret;
159 	}
160 
161 	return scmi_status_to_errno(status);
162 }
163