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