xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/scmi-msg/clock.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park // SPDX-License-Identifier: BSD-3-Clause
2*54fd6939SJiyong Park /*
3*54fd6939SJiyong Park  * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
4*54fd6939SJiyong Park  * Copyright (c) 2019-2020, Linaro Limited
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park #include <cdefs.h>
7*54fd6939SJiyong Park #include <string.h>
8*54fd6939SJiyong Park 
9*54fd6939SJiyong Park #include <drivers/scmi-msg.h>
10*54fd6939SJiyong Park #include <drivers/scmi.h>
11*54fd6939SJiyong Park #include <lib/utils_def.h>
12*54fd6939SJiyong Park 
13*54fd6939SJiyong Park #include "common.h"
14*54fd6939SJiyong Park 
15*54fd6939SJiyong Park #pragma weak plat_scmi_clock_count
16*54fd6939SJiyong Park #pragma weak plat_scmi_clock_get_name
17*54fd6939SJiyong Park #pragma weak plat_scmi_clock_rates_array
18*54fd6939SJiyong Park #pragma weak plat_scmi_clock_rates_by_step
19*54fd6939SJiyong Park #pragma weak plat_scmi_clock_get_rate
20*54fd6939SJiyong Park #pragma weak plat_scmi_clock_set_rate
21*54fd6939SJiyong Park #pragma weak plat_scmi_clock_get_state
22*54fd6939SJiyong Park #pragma weak plat_scmi_clock_set_state
23*54fd6939SJiyong Park 
24*54fd6939SJiyong Park static bool message_id_is_supported(unsigned int message_id);
25*54fd6939SJiyong Park 
plat_scmi_clock_count(unsigned int agent_id __unused)26*54fd6939SJiyong Park size_t plat_scmi_clock_count(unsigned int agent_id __unused)
27*54fd6939SJiyong Park {
28*54fd6939SJiyong Park 	return 0U;
29*54fd6939SJiyong Park }
30*54fd6939SJiyong Park 
plat_scmi_clock_get_name(unsigned int agent_id __unused,unsigned int scmi_id __unused)31*54fd6939SJiyong Park const char *plat_scmi_clock_get_name(unsigned int agent_id __unused,
32*54fd6939SJiyong Park 				     unsigned int scmi_id __unused)
33*54fd6939SJiyong Park {
34*54fd6939SJiyong Park 	return NULL;
35*54fd6939SJiyong Park }
36*54fd6939SJiyong Park 
plat_scmi_clock_rates_array(unsigned int agent_id __unused,unsigned int scmi_id __unused,unsigned long * rates __unused,size_t * nb_elts __unused)37*54fd6939SJiyong Park int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused,
38*54fd6939SJiyong Park 				    unsigned int scmi_id __unused,
39*54fd6939SJiyong Park 				    unsigned long *rates __unused,
40*54fd6939SJiyong Park 				    size_t *nb_elts __unused)
41*54fd6939SJiyong Park {
42*54fd6939SJiyong Park 	return SCMI_NOT_SUPPORTED;
43*54fd6939SJiyong Park }
44*54fd6939SJiyong Park 
plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,unsigned int scmi_id __unused,unsigned long * steps __unused)45*54fd6939SJiyong Park int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
46*54fd6939SJiyong Park 				      unsigned int scmi_id __unused,
47*54fd6939SJiyong Park 				      unsigned long *steps __unused)
48*54fd6939SJiyong Park {
49*54fd6939SJiyong Park 	return SCMI_NOT_SUPPORTED;
50*54fd6939SJiyong Park }
51*54fd6939SJiyong Park 
plat_scmi_clock_get_rate(unsigned int agent_id __unused,unsigned int scmi_id __unused)52*54fd6939SJiyong Park unsigned long plat_scmi_clock_get_rate(unsigned int agent_id __unused,
53*54fd6939SJiyong Park 				       unsigned int scmi_id __unused)
54*54fd6939SJiyong Park {
55*54fd6939SJiyong Park 	return 0U;
56*54fd6939SJiyong Park }
57*54fd6939SJiyong Park 
plat_scmi_clock_set_rate(unsigned int agent_id __unused,unsigned int scmi_id __unused,unsigned long rate __unused)58*54fd6939SJiyong Park int32_t plat_scmi_clock_set_rate(unsigned int agent_id __unused,
59*54fd6939SJiyong Park 				 unsigned int scmi_id __unused,
60*54fd6939SJiyong Park 				 unsigned long rate __unused)
61*54fd6939SJiyong Park {
62*54fd6939SJiyong Park 	return SCMI_NOT_SUPPORTED;
63*54fd6939SJiyong Park }
64*54fd6939SJiyong Park 
plat_scmi_clock_get_state(unsigned int agent_id __unused,unsigned int scmi_id __unused)65*54fd6939SJiyong Park int32_t plat_scmi_clock_get_state(unsigned int agent_id __unused,
66*54fd6939SJiyong Park 				  unsigned int scmi_id __unused)
67*54fd6939SJiyong Park {
68*54fd6939SJiyong Park 	return SCMI_NOT_SUPPORTED;
69*54fd6939SJiyong Park }
70*54fd6939SJiyong Park 
plat_scmi_clock_set_state(unsigned int agent_id __unused,unsigned int scmi_id __unused,bool enable_not_disable __unused)71*54fd6939SJiyong Park int32_t plat_scmi_clock_set_state(unsigned int agent_id __unused,
72*54fd6939SJiyong Park 				  unsigned int scmi_id __unused,
73*54fd6939SJiyong Park 				  bool enable_not_disable __unused)
74*54fd6939SJiyong Park {
75*54fd6939SJiyong Park 	return SCMI_NOT_SUPPORTED;
76*54fd6939SJiyong Park }
77*54fd6939SJiyong Park 
report_version(struct scmi_msg * msg)78*54fd6939SJiyong Park static void report_version(struct scmi_msg *msg)
79*54fd6939SJiyong Park {
80*54fd6939SJiyong Park 	struct scmi_protocol_version_p2a return_values = {
81*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
82*54fd6939SJiyong Park 		.version = SCMI_PROTOCOL_VERSION_CLOCK,
83*54fd6939SJiyong Park 	};
84*54fd6939SJiyong Park 
85*54fd6939SJiyong Park 	if (msg->in_size != 0) {
86*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
87*54fd6939SJiyong Park 		return;
88*54fd6939SJiyong Park 	}
89*54fd6939SJiyong Park 
90*54fd6939SJiyong Park 	scmi_write_response(msg, &return_values, sizeof(return_values));
91*54fd6939SJiyong Park }
92*54fd6939SJiyong Park 
report_attributes(struct scmi_msg * msg)93*54fd6939SJiyong Park static void report_attributes(struct scmi_msg *msg)
94*54fd6939SJiyong Park {
95*54fd6939SJiyong Park 	size_t agent_count = plat_scmi_clock_count(msg->agent_id);
96*54fd6939SJiyong Park 	struct scmi_protocol_attributes_p2a return_values = {
97*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
98*54fd6939SJiyong Park 		.attributes = SCMI_CLOCK_PROTOCOL_ATTRIBUTES(1U, agent_count),
99*54fd6939SJiyong Park 	};
100*54fd6939SJiyong Park 
101*54fd6939SJiyong Park 	if (msg->in_size != 0) {
102*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
103*54fd6939SJiyong Park 		return;
104*54fd6939SJiyong Park 	}
105*54fd6939SJiyong Park 
106*54fd6939SJiyong Park 	scmi_write_response(msg, &return_values, sizeof(return_values));
107*54fd6939SJiyong Park }
108*54fd6939SJiyong Park 
report_message_attributes(struct scmi_msg * msg)109*54fd6939SJiyong Park static void report_message_attributes(struct scmi_msg *msg)
110*54fd6939SJiyong Park {
111*54fd6939SJiyong Park 	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
112*54fd6939SJiyong Park 	struct scmi_protocol_message_attributes_p2a return_values = {
113*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
114*54fd6939SJiyong Park 		/* For this protocol, attributes shall be zero */
115*54fd6939SJiyong Park 		.attributes = 0U,
116*54fd6939SJiyong Park 	};
117*54fd6939SJiyong Park 
118*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
119*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
120*54fd6939SJiyong Park 		return;
121*54fd6939SJiyong Park 	}
122*54fd6939SJiyong Park 
123*54fd6939SJiyong Park 	if (!message_id_is_supported(in_args->message_id)) {
124*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_NOT_FOUND);
125*54fd6939SJiyong Park 		return;
126*54fd6939SJiyong Park 	}
127*54fd6939SJiyong Park 
128*54fd6939SJiyong Park 	scmi_write_response(msg, &return_values, sizeof(return_values));
129*54fd6939SJiyong Park }
130*54fd6939SJiyong Park 
scmi_clock_attributes(struct scmi_msg * msg)131*54fd6939SJiyong Park static void scmi_clock_attributes(struct scmi_msg *msg)
132*54fd6939SJiyong Park {
133*54fd6939SJiyong Park 	const struct scmi_clock_attributes_a2p *in_args = (void *)msg->in;
134*54fd6939SJiyong Park 	struct scmi_clock_attributes_p2a return_values = {
135*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
136*54fd6939SJiyong Park 	};
137*54fd6939SJiyong Park 	const char *name = NULL;
138*54fd6939SJiyong Park 	unsigned int clock_id = 0U;
139*54fd6939SJiyong Park 
140*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
141*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
142*54fd6939SJiyong Park 		return;
143*54fd6939SJiyong Park 	}
144*54fd6939SJiyong Park 
145*54fd6939SJiyong Park 	clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
146*54fd6939SJiyong Park 
147*54fd6939SJiyong Park 	if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
148*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
149*54fd6939SJiyong Park 		return;
150*54fd6939SJiyong Park 	}
151*54fd6939SJiyong Park 
152*54fd6939SJiyong Park 
153*54fd6939SJiyong Park 	name = plat_scmi_clock_get_name(msg->agent_id, clock_id);
154*54fd6939SJiyong Park 	if (name == NULL) {
155*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_NOT_FOUND);
156*54fd6939SJiyong Park 		return;
157*54fd6939SJiyong Park 	}
158*54fd6939SJiyong Park 
159*54fd6939SJiyong Park 	COPY_NAME_IDENTIFIER(return_values.clock_name, name);
160*54fd6939SJiyong Park 
161*54fd6939SJiyong Park 	return_values.attributes = plat_scmi_clock_get_state(msg->agent_id,
162*54fd6939SJiyong Park 							     clock_id);
163*54fd6939SJiyong Park 
164*54fd6939SJiyong Park 	scmi_write_response(msg, &return_values, sizeof(return_values));
165*54fd6939SJiyong Park }
166*54fd6939SJiyong Park 
scmi_clock_rate_get(struct scmi_msg * msg)167*54fd6939SJiyong Park static void scmi_clock_rate_get(struct scmi_msg *msg)
168*54fd6939SJiyong Park {
169*54fd6939SJiyong Park 	const struct scmi_clock_rate_get_a2p *in_args = (void *)msg->in;
170*54fd6939SJiyong Park 	unsigned long rate = 0U;
171*54fd6939SJiyong Park 	struct scmi_clock_rate_get_p2a return_values = {
172*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
173*54fd6939SJiyong Park 	};
174*54fd6939SJiyong Park 	unsigned int clock_id = 0U;
175*54fd6939SJiyong Park 
176*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
177*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
178*54fd6939SJiyong Park 		return;
179*54fd6939SJiyong Park 	}
180*54fd6939SJiyong Park 
181*54fd6939SJiyong Park 	clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
182*54fd6939SJiyong Park 
183*54fd6939SJiyong Park 	if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
184*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
185*54fd6939SJiyong Park 		return;
186*54fd6939SJiyong Park 	}
187*54fd6939SJiyong Park 
188*54fd6939SJiyong Park 	rate = plat_scmi_clock_get_rate(msg->agent_id, clock_id);
189*54fd6939SJiyong Park 
190*54fd6939SJiyong Park 	return_values.rate[0] = (uint32_t)rate;
191*54fd6939SJiyong Park 	return_values.rate[1] = (uint32_t)((uint64_t)rate >> 32);
192*54fd6939SJiyong Park 
193*54fd6939SJiyong Park 	scmi_write_response(msg, &return_values, sizeof(return_values));
194*54fd6939SJiyong Park }
195*54fd6939SJiyong Park 
scmi_clock_rate_set(struct scmi_msg * msg)196*54fd6939SJiyong Park static void scmi_clock_rate_set(struct scmi_msg *msg)
197*54fd6939SJiyong Park {
198*54fd6939SJiyong Park 	const struct scmi_clock_rate_set_a2p *in_args = (void *)msg->in;
199*54fd6939SJiyong Park 	unsigned long rate = 0U;
200*54fd6939SJiyong Park 	int32_t status = 0;
201*54fd6939SJiyong Park 	unsigned int clock_id = 0U;
202*54fd6939SJiyong Park 
203*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
204*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
205*54fd6939SJiyong Park 		return;
206*54fd6939SJiyong Park 	}
207*54fd6939SJiyong Park 
208*54fd6939SJiyong Park 	clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
209*54fd6939SJiyong Park 
210*54fd6939SJiyong Park 	if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
211*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
212*54fd6939SJiyong Park 		return;
213*54fd6939SJiyong Park 	}
214*54fd6939SJiyong Park 
215*54fd6939SJiyong Park 	rate = (unsigned long)(((uint64_t)in_args->rate[1] << 32) |
216*54fd6939SJiyong Park 			       in_args->rate[0]);
217*54fd6939SJiyong Park 
218*54fd6939SJiyong Park 	status = plat_scmi_clock_set_rate(msg->agent_id, clock_id, rate);
219*54fd6939SJiyong Park 
220*54fd6939SJiyong Park 	scmi_status_response(msg, status);
221*54fd6939SJiyong Park }
222*54fd6939SJiyong Park 
scmi_clock_config_set(struct scmi_msg * msg)223*54fd6939SJiyong Park static void scmi_clock_config_set(struct scmi_msg *msg)
224*54fd6939SJiyong Park {
225*54fd6939SJiyong Park 	const struct scmi_clock_config_set_a2p *in_args = (void *)msg->in;
226*54fd6939SJiyong Park 	int32_t status = SCMI_GENERIC_ERROR;
227*54fd6939SJiyong Park 	bool enable = false;
228*54fd6939SJiyong Park 	unsigned int clock_id = 0U;
229*54fd6939SJiyong Park 
230*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
231*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
232*54fd6939SJiyong Park 		return;
233*54fd6939SJiyong Park 	}
234*54fd6939SJiyong Park 
235*54fd6939SJiyong Park 	clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
236*54fd6939SJiyong Park 
237*54fd6939SJiyong Park 	if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
238*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
239*54fd6939SJiyong Park 		return;
240*54fd6939SJiyong Park 	}
241*54fd6939SJiyong Park 
242*54fd6939SJiyong Park 	enable = in_args->attributes & SCMI_CLOCK_CONFIG_SET_ENABLE_MASK;
243*54fd6939SJiyong Park 
244*54fd6939SJiyong Park 	status = plat_scmi_clock_set_state(msg->agent_id, clock_id, enable);
245*54fd6939SJiyong Park 
246*54fd6939SJiyong Park 	scmi_status_response(msg, status);
247*54fd6939SJiyong Park }
248*54fd6939SJiyong Park 
249*54fd6939SJiyong Park #define RATES_ARRAY_SIZE_MAX	(SCMI_PLAYLOAD_MAX - \
250*54fd6939SJiyong Park 				 sizeof(struct scmi_clock_describe_rates_p2a))
251*54fd6939SJiyong Park 
252*54fd6939SJiyong Park #define SCMI_RATES_BY_ARRAY(_nb_rates, _rem_rates) \
253*54fd6939SJiyong Park 	SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS((_nb_rates), \
254*54fd6939SJiyong Park 						SCMI_CLOCK_RATE_FORMAT_LIST, \
255*54fd6939SJiyong Park 						(_rem_rates))
256*54fd6939SJiyong Park #define SCMI_RATES_BY_STEP \
257*54fd6939SJiyong Park 	SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(3U, \
258*54fd6939SJiyong Park 						SCMI_CLOCK_RATE_FORMAT_RANGE, \
259*54fd6939SJiyong Park 						0U)
260*54fd6939SJiyong Park 
261*54fd6939SJiyong Park #define RATE_DESC_SIZE		sizeof(struct scmi_clock_rate)
262*54fd6939SJiyong Park 
write_rate_desc_array_in_buffer(char * dest,unsigned long * rates,size_t nb_elt)263*54fd6939SJiyong Park static void write_rate_desc_array_in_buffer(char *dest, unsigned long *rates,
264*54fd6939SJiyong Park 					    size_t nb_elt)
265*54fd6939SJiyong Park {
266*54fd6939SJiyong Park 	uint32_t *out = (uint32_t *)(uintptr_t)dest;
267*54fd6939SJiyong Park 	size_t n;
268*54fd6939SJiyong Park 
269*54fd6939SJiyong Park 	ASSERT_SYM_PTR_ALIGN(out);
270*54fd6939SJiyong Park 
271*54fd6939SJiyong Park 	for (n = 0U; n < nb_elt; n++) {
272*54fd6939SJiyong Park 		out[2 * n] = (uint32_t)rates[n];
273*54fd6939SJiyong Park 		out[2 * n + 1] = (uint32_t)((uint64_t)rates[n] >> 32);
274*54fd6939SJiyong Park 	}
275*54fd6939SJiyong Park }
276*54fd6939SJiyong Park 
scmi_clock_describe_rates(struct scmi_msg * msg)277*54fd6939SJiyong Park static void scmi_clock_describe_rates(struct scmi_msg *msg)
278*54fd6939SJiyong Park {
279*54fd6939SJiyong Park 	const struct scmi_clock_describe_rates_a2p *in_args = (void *)msg->in;
280*54fd6939SJiyong Park 	struct scmi_clock_describe_rates_p2a p2a = {
281*54fd6939SJiyong Park 		.status = SCMI_SUCCESS,
282*54fd6939SJiyong Park 	};
283*54fd6939SJiyong Park 	size_t nb_rates;
284*54fd6939SJiyong Park 	int32_t status;
285*54fd6939SJiyong Park 	unsigned int clock_id;
286*54fd6939SJiyong Park 
287*54fd6939SJiyong Park 	if (msg->in_size != sizeof(*in_args)) {
288*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
289*54fd6939SJiyong Park 		return;
290*54fd6939SJiyong Park 	}
291*54fd6939SJiyong Park 
292*54fd6939SJiyong Park 	clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
293*54fd6939SJiyong Park 
294*54fd6939SJiyong Park 	if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
295*54fd6939SJiyong Park 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
296*54fd6939SJiyong Park 		return;
297*54fd6939SJiyong Park 	}
298*54fd6939SJiyong Park 
299*54fd6939SJiyong Park 	/* Platform may support array rate description */
300*54fd6939SJiyong Park 	status = plat_scmi_clock_rates_array(msg->agent_id, clock_id, NULL,
301*54fd6939SJiyong Park 					     &nb_rates);
302*54fd6939SJiyong Park 	if (status == SCMI_SUCCESS) {
303*54fd6939SJiyong Park 		/* Currently 12 cells mex, so it's affordable for the stack */
304*54fd6939SJiyong Park 		unsigned long plat_rates[RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE];
305*54fd6939SJiyong Park 		size_t max_nb = RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE;
306*54fd6939SJiyong Park 		size_t ret_nb = MIN(nb_rates - in_args->rate_index, max_nb);
307*54fd6939SJiyong Park 		size_t rem_nb = nb_rates - in_args->rate_index - ret_nb;
308*54fd6939SJiyong Park 
309*54fd6939SJiyong Park 		status =  plat_scmi_clock_rates_array(msg->agent_id, clock_id,
310*54fd6939SJiyong Park 						      plat_rates, &ret_nb);
311*54fd6939SJiyong Park 		if (status == SCMI_SUCCESS) {
312*54fd6939SJiyong Park 			write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
313*54fd6939SJiyong Park 							plat_rates, ret_nb);
314*54fd6939SJiyong Park 
315*54fd6939SJiyong Park 			p2a.num_rates_flags = SCMI_RATES_BY_ARRAY(ret_nb,
316*54fd6939SJiyong Park 								  rem_nb);
317*54fd6939SJiyong Park 			p2a.status = SCMI_SUCCESS;
318*54fd6939SJiyong Park 
319*54fd6939SJiyong Park 			memcpy(msg->out, &p2a, sizeof(p2a));
320*54fd6939SJiyong Park 			msg->out_size_out = sizeof(p2a) +
321*54fd6939SJiyong Park 					    ret_nb * RATE_DESC_SIZE;
322*54fd6939SJiyong Park 		}
323*54fd6939SJiyong Park 	} else if (status == SCMI_NOT_SUPPORTED) {
324*54fd6939SJiyong Park 		unsigned long triplet[3] = { 0U, 0U, 0U };
325*54fd6939SJiyong Park 
326*54fd6939SJiyong Park 		/* Platform may support min§max/step triplet description */
327*54fd6939SJiyong Park 		status =  plat_scmi_clock_rates_by_step(msg->agent_id, clock_id,
328*54fd6939SJiyong Park 							triplet);
329*54fd6939SJiyong Park 		if (status == SCMI_SUCCESS) {
330*54fd6939SJiyong Park 			write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
331*54fd6939SJiyong Park 							triplet, 3U);
332*54fd6939SJiyong Park 
333*54fd6939SJiyong Park 			p2a.num_rates_flags = SCMI_RATES_BY_STEP;
334*54fd6939SJiyong Park 			p2a.status = SCMI_SUCCESS;
335*54fd6939SJiyong Park 
336*54fd6939SJiyong Park 			memcpy(msg->out, &p2a, sizeof(p2a));
337*54fd6939SJiyong Park 			msg->out_size_out = sizeof(p2a) + (3U * RATE_DESC_SIZE);
338*54fd6939SJiyong Park 		}
339*54fd6939SJiyong Park 	} else {
340*54fd6939SJiyong Park 		/* Fallthrough generic exit sequence below with error status */
341*54fd6939SJiyong Park 	}
342*54fd6939SJiyong Park 
343*54fd6939SJiyong Park 	if (status != SCMI_SUCCESS) {
344*54fd6939SJiyong Park 		scmi_status_response(msg, status);
345*54fd6939SJiyong Park 	} else {
346*54fd6939SJiyong Park 		/*
347*54fd6939SJiyong Park 		 * Message payload is already writen to msg->out, and
348*54fd6939SJiyong Park 		 * msg->out_size_out updated.
349*54fd6939SJiyong Park 		 */
350*54fd6939SJiyong Park 	}
351*54fd6939SJiyong Park }
352*54fd6939SJiyong Park 
353*54fd6939SJiyong Park static const scmi_msg_handler_t scmi_clock_handler_table[] = {
354*54fd6939SJiyong Park 	[SCMI_PROTOCOL_VERSION] = report_version,
355*54fd6939SJiyong Park 	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
356*54fd6939SJiyong Park 	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
357*54fd6939SJiyong Park 	[SCMI_CLOCK_ATTRIBUTES] = scmi_clock_attributes,
358*54fd6939SJiyong Park 	[SCMI_CLOCK_DESCRIBE_RATES] = scmi_clock_describe_rates,
359*54fd6939SJiyong Park 	[SCMI_CLOCK_RATE_SET] = scmi_clock_rate_set,
360*54fd6939SJiyong Park 	[SCMI_CLOCK_RATE_GET] = scmi_clock_rate_get,
361*54fd6939SJiyong Park 	[SCMI_CLOCK_CONFIG_SET] = scmi_clock_config_set,
362*54fd6939SJiyong Park };
363*54fd6939SJiyong Park 
message_id_is_supported(size_t message_id)364*54fd6939SJiyong Park static bool message_id_is_supported(size_t message_id)
365*54fd6939SJiyong Park {
366*54fd6939SJiyong Park 	return (message_id < ARRAY_SIZE(scmi_clock_handler_table)) &&
367*54fd6939SJiyong Park 	       (scmi_clock_handler_table[message_id] != NULL);
368*54fd6939SJiyong Park }
369*54fd6939SJiyong Park 
scmi_msg_get_clock_handler(struct scmi_msg * msg)370*54fd6939SJiyong Park scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg)
371*54fd6939SJiyong Park {
372*54fd6939SJiyong Park 	const size_t array_size = ARRAY_SIZE(scmi_clock_handler_table);
373*54fd6939SJiyong Park 	unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
374*54fd6939SJiyong Park 
375*54fd6939SJiyong Park 	if (message_id >= array_size) {
376*54fd6939SJiyong Park 		VERBOSE("Clock handle not found %u", msg->message_id);
377*54fd6939SJiyong Park 		return NULL;
378*54fd6939SJiyong Park 	}
379*54fd6939SJiyong Park 
380*54fd6939SJiyong Park 	return scmi_clock_handler_table[message_id];
381*54fd6939SJiyong Park }
382