1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/firmware/scmi/clk.h>
8 #include <string.h>
9
10 /* TODO: if extended attributes are supported this should be moved
11 * to the header file so that users will have access to it.
12 */
13 #define SCMI_CLK_CONFIG_EA_MASK GENMASK(23, 16)
14
15 struct scmi_clock_attributes_reply {
16 int32_t status;
17 uint32_t attributes;
18 };
19
20 struct scmi_clock_rate_set_reply {
21 int32_t status;
22 uint32_t rate[2];
23 };
24
25 struct scmi_clock_parent_get_reply {
26 int32_t status;
27 uint32_t parent_id;
28 };
29
30 struct scmi_clock_parent_config {
31 uint32_t clk_id;
32 uint32_t parent_id;
33 };
34
scmi_clock_rate_get(struct scmi_protocol * proto,uint32_t clk_id,uint32_t * rate)35 int scmi_clock_rate_get(struct scmi_protocol *proto,
36 uint32_t clk_id, uint32_t *rate)
37 {
38 struct scmi_message msg, reply;
39 int ret;
40 struct scmi_clock_rate_set_reply reply_buffer;
41
42 /* sanity checks */
43 if (!proto || !rate) {
44 return -EINVAL;
45 }
46
47 if (proto->id != SCMI_PROTOCOL_CLOCK) {
48 return -EINVAL;
49 }
50
51 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_RATE_GET,
52 SCMI_COMMAND, proto->id, 0x0);
53 msg.len = sizeof(clk_id);
54 msg.content = &clk_id;
55
56 reply.hdr = msg.hdr;
57 reply.len = sizeof(reply_buffer);
58 reply.content = &reply_buffer;
59
60 ret = scmi_send_message(proto, &msg, &reply);
61 if (ret < 0) {
62 return ret;
63 }
64
65 if (reply_buffer.status != SCMI_SUCCESS) {
66 return scmi_status_to_errno(reply_buffer.status);
67 }
68
69 *rate = reply_buffer.rate[0];
70
71 return 0;
72 }
73
scmi_clock_rate_set(struct scmi_protocol * proto,struct scmi_clock_rate_config * cfg)74 int scmi_clock_rate_set(struct scmi_protocol *proto, struct scmi_clock_rate_config *cfg)
75 {
76 struct scmi_message msg, reply;
77 int status, ret;
78
79 /* sanity checks */
80 if (!proto || !cfg) {
81 return -EINVAL;
82 }
83
84 if (proto->id != SCMI_PROTOCOL_CLOCK) {
85 return -EINVAL;
86 }
87
88 /* Currently ASYNC flag is not supported. */
89 if (cfg->flags & SCMI_CLK_RATE_SET_FLAGS_ASYNC) {
90 return -ENOTSUP;
91 }
92
93 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_RATE_SET, SCMI_COMMAND, proto->id, 0x0);
94 msg.len = sizeof(*cfg);
95 msg.content = cfg;
96
97 reply.hdr = msg.hdr;
98 reply.len = sizeof(status);
99 reply.content = &status;
100
101 ret = scmi_send_message(proto, &msg, &reply);
102 if (ret < 0) {
103 return ret;
104 }
105
106 if (status != SCMI_SUCCESS) {
107 return scmi_status_to_errno(status);
108 }
109
110 return 0;
111 }
112
scmi_clock_parent_get(struct scmi_protocol * proto,uint32_t clk_id,uint32_t * parent_id)113 int scmi_clock_parent_get(struct scmi_protocol *proto, uint32_t clk_id, uint32_t *parent_id)
114 {
115 struct scmi_message msg, reply;
116 int ret;
117 struct scmi_clock_parent_get_reply reply_buffer;
118
119 /* sanity checks */
120 if (!proto || !parent_id) {
121 return -EINVAL;
122 }
123
124 if (proto->id != SCMI_PROTOCOL_CLOCK) {
125 return -EINVAL;
126 }
127
128 msg.hdr =
129 SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_PARENT_GET, SCMI_COMMAND, proto->id, 0x0);
130 msg.len = sizeof(clk_id);
131 msg.content = &clk_id;
132
133 reply.hdr = msg.hdr;
134 reply.len = sizeof(reply_buffer);
135 reply.content = &reply_buffer;
136
137 ret = scmi_send_message(proto, &msg, &reply);
138 if (ret < 0) {
139 return ret;
140 }
141
142 if (reply_buffer.status != SCMI_SUCCESS) {
143 return scmi_status_to_errno(reply_buffer.status);
144 }
145
146 *parent_id = reply_buffer.parent_id;
147
148 return 0;
149 }
150
scmi_clock_parent_set(struct scmi_protocol * proto,uint32_t clk_id,uint32_t parent_id)151 int scmi_clock_parent_set(struct scmi_protocol *proto, uint32_t clk_id, uint32_t parent_id)
152 {
153 struct scmi_clock_parent_config cfg = {.clk_id = clk_id, .parent_id = parent_id};
154 struct scmi_message msg, reply;
155 int status, ret;
156
157 /* sanity checks */
158 if (!proto) {
159 return -EINVAL;
160 }
161
162 if (proto->id != SCMI_PROTOCOL_CLOCK) {
163 return -EINVAL;
164 }
165
166 msg.hdr =
167 SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_PARENT_SET, SCMI_COMMAND, proto->id, 0x0);
168 msg.len = sizeof(cfg);
169 msg.content = &cfg;
170
171 reply.hdr = msg.hdr;
172 reply.len = sizeof(status);
173 reply.content = &status;
174
175 ret = scmi_send_message(proto, &msg, &reply);
176 if (ret < 0) {
177 return ret;
178 }
179
180 if (status != SCMI_SUCCESS) {
181 return scmi_status_to_errno(status);
182 }
183
184 return 0;
185 }
186
scmi_clock_config_set(struct scmi_protocol * proto,struct scmi_clock_config * cfg)187 int scmi_clock_config_set(struct scmi_protocol *proto,
188 struct scmi_clock_config *cfg)
189 {
190 struct scmi_message msg, reply;
191 int status, ret;
192
193 /* sanity checks */
194 if (!proto || !cfg) {
195 return -EINVAL;
196 }
197
198 if (proto->id != SCMI_PROTOCOL_CLOCK) {
199 return -EINVAL;
200 }
201
202 /* extended attributes currently not supported */
203 if (cfg->attributes & SCMI_CLK_CONFIG_EA_MASK) {
204 return -ENOTSUP;
205 }
206
207 /* invalid because extended attributes are not supported */
208 if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 3) {
209 return -ENOTSUP;
210 }
211
212 /* this is a reserved value */
213 if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 2) {
214 return -EINVAL;
215 }
216
217 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_CONFIG_SET,
218 SCMI_COMMAND, proto->id, 0x0);
219 msg.len = sizeof(*cfg);
220 msg.content = cfg;
221
222 reply.hdr = msg.hdr;
223 reply.len = sizeof(status);
224 reply.content = &status;
225
226 ret = scmi_send_message(proto, &msg, &reply);
227 if (ret < 0) {
228 return ret;
229 }
230
231 if (status != SCMI_SUCCESS) {
232 return scmi_status_to_errno(status);
233 }
234
235 return 0;
236 }
237
scmi_clock_protocol_attributes(struct scmi_protocol * proto,uint32_t * attributes)238 int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attributes)
239 {
240 struct scmi_message msg, reply;
241 struct scmi_clock_attributes_reply reply_buffer;
242 int ret;
243
244 /* sanity checks */
245 if (!proto || !attributes) {
246 return -EINVAL;
247 }
248
249 if (proto->id != SCMI_PROTOCOL_CLOCK) {
250 return -EINVAL;
251 }
252
253 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_PROTOCOL_ATTRIBUTES,
254 SCMI_COMMAND, proto->id, 0x0);
255 /* command has no parameters */
256 msg.len = 0x0;
257 msg.content = NULL;
258
259 reply.hdr = msg.hdr;
260 reply.len = sizeof(reply_buffer);
261 reply.content = &reply_buffer;
262
263 ret = scmi_send_message(proto, &msg, &reply);
264 if (ret < 0) {
265 return ret;
266 }
267
268 if (reply_buffer.status != 0) {
269 return scmi_status_to_errno(reply_buffer.status);
270 }
271
272 *attributes = reply_buffer.attributes;
273
274 return 0;
275 }
276