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