FILE
voltage.c
File preview with syntax highlighting.
linux-6.19.14/drivers/firmware/arm_scmi/voltage.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * System Control and Management Interface (SCMI) Voltage Protocol 4 * 5 * Copyright (C) 2020-2022 ARM Ltd. 6 */ 7 8#include <linux/module.h> 9#include <linux/scmi_protocol.h> 10 11#include "protocols.h" 12 13/* Updated only after ALL the mandatory features for that version are merged */ 14#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 15 16#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) 17#define REMAINING_LEVELS_MASK GENMASK(31, 16) 18#define RETURNED_LEVELS_MASK GENMASK(11, 0) 19 20enum scmi_voltage_protocol_cmd { 21 VOLTAGE_DOMAIN_ATTRIBUTES = 0x3, 22 VOLTAGE_DESCRIBE_LEVELS = 0x4, 23 VOLTAGE_CONFIG_SET = 0x5, 24 VOLTAGE_CONFIG_GET = 0x6, 25 VOLTAGE_LEVEL_SET = 0x7, 26 VOLTAGE_LEVEL_GET = 0x8, 27 VOLTAGE_DOMAIN_NAME_GET = 0x09, 28}; 29 30#define NUM_VOLTAGE_DOMAINS(x) ((u16)(FIELD_GET(VOLTAGE_DOMS_NUM_MASK, (x)))) 31 32struct scmi_msg_resp_domain_attributes { 33 __le32 attr; 34#define SUPPORTS_ASYNC_LEVEL_SET(x) ((x) & BIT(31)) 35#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(30)) 36 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 37}; 38 39struct scmi_msg_cmd_describe_levels { 40 __le32 domain_id; 41 __le32 level_index; 42}; 43 44struct scmi_msg_resp_describe_levels { 45 __le32 flags; 46#define NUM_REMAINING_LEVELS(f) ((u16)(FIELD_GET(REMAINING_LEVELS_MASK, (f)))) 47#define NUM_RETURNED_LEVELS(f) ((u16)(FIELD_GET(RETURNED_LEVELS_MASK, (f)))) 48#define SUPPORTS_SEGMENTED_LEVELS(f) ((f) & BIT(12)) 49 __le32 voltage[]; 50}; 51 52struct scmi_msg_cmd_config_set { 53 __le32 domain_id; 54 __le32 config; 55}; 56 57struct scmi_msg_cmd_level_set { 58 __le32 domain_id; 59 __le32 flags; 60 __le32 voltage_level; 61}; 62 63struct scmi_resp_voltage_level_set_complete { 64 __le32 domain_id; 65 __le32 voltage_level; 66}; 67 68struct voltage_info { 69 unsigned int version; 70 unsigned int num_domains; 71 struct scmi_voltage_info *domains; 72}; 73 74static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph, 75 struct voltage_info *vinfo) 76{ 77 int ret; 78 struct scmi_xfer *t; 79 80 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, 81 sizeof(__le32), &t); 82 if (ret) 83 return ret; 84 85 ret = ph->xops->do_xfer(ph, t); 86 if (!ret) 87 vinfo->num_domains = 88 NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf)); 89 90 ph->xops->xfer_put(ph, t); 91 return ret; 92} 93 94static int scmi_init_voltage_levels(struct device *dev, 95 struct scmi_voltage_info *v, 96 u32 num_returned, u32 num_remaining, 97 bool segmented) 98{ 99 u32 num_levels; 100 101 num_levels = num_returned + num_remaining; 102 /* 103 * segmented levels entries are represented by a single triplet 104 * returned all in one go. 105 */ 106 if (!num_levels || 107 (segmented && (num_remaining || num_returned != 3))) { 108 dev_err(dev, 109 "Invalid level descriptor(%d/%d/%d) for voltage dom %d\n", 110 num_levels, num_returned, num_remaining, v->id); 111 return -EINVAL; 112 } 113 114 v->levels_uv = devm_kcalloc(dev, num_levels, sizeof(u32), GFP_KERNEL); 115 if (!v->levels_uv) 116 return -ENOMEM; 117 118 v->num_levels = num_levels; 119 v->segmented = segmented; 120 121 return 0; 122} 123 124struct scmi_volt_ipriv { 125 struct device *dev; 126 struct scmi_voltage_info *v; 127}; 128 129static void iter_volt_levels_prepare_message(void *message, 130 unsigned int desc_index, 131 const void *priv) 132{ 133 struct scmi_msg_cmd_describe_levels *msg = message; 134 const struct scmi_volt_ipriv *p = priv; 135 136 msg->domain_id = cpu_to_le32(p->v->id); 137 msg->level_index = cpu_to_le32(desc_index); 138} 139 140static int iter_volt_levels_update_state(struct scmi_iterator_state *st, 141 const void *response, void *priv) 142{ 143 int ret = 0; 144 u32 flags; 145 const struct scmi_msg_resp_describe_levels *r = response; 146 struct scmi_volt_ipriv *p = priv; 147 148 flags = le32_to_cpu(r->flags); 149 st->num_returned = NUM_RETURNED_LEVELS(flags); 150 st->num_remaining = NUM_REMAINING_LEVELS(flags); 151 152 /* Allocate space for num_levels if not already done */ 153 if (!p->v->num_levels) { 154 ret = scmi_init_voltage_levels(p->dev, p->v, st->num_returned, 155 st->num_remaining, 156 SUPPORTS_SEGMENTED_LEVELS(flags)); 157 if (!ret) 158 st->max_resources = p->v->num_levels; 159 } 160 161 return ret; 162} 163 164static int 165iter_volt_levels_process_response(const struct scmi_protocol_handle *ph, 166 const void *response, 167 struct scmi_iterator_state *st, void *priv) 168{ 169 s32 val; 170 const struct scmi_msg_resp_describe_levels *r = response; 171 struct scmi_volt_ipriv *p = priv; 172 173 val = (s32)le32_to_cpu(r->voltage[st->loop_idx]); 174 p->v->levels_uv[st->desc_index + st->loop_idx] = val; 175 if (val < 0) 176 p->v->negative_volts_allowed = true; 177 178 return 0; 179} 180 181static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph, 182 struct scmi_voltage_info *v) 183{ 184 int ret; 185 void *iter; 186 struct scmi_iterator_ops ops = { 187 .prepare_message = iter_volt_levels_prepare_message, 188 .update_state = iter_volt_levels_update_state, 189 .process_response = iter_volt_levels_process_response, 190 }; 191 struct scmi_volt_ipriv vpriv = { 192 .dev = ph->dev, 193 .v = v, 194 }; 195 196 iter = ph->hops->iter_response_init(ph, &ops, v->num_levels, 197 VOLTAGE_DESCRIBE_LEVELS, 198 sizeof(struct scmi_msg_cmd_describe_levels), 199 &vpriv); 200 if (IS_ERR(iter)) 201 return PTR_ERR(iter); 202 203 ret = ph->hops->iter_response_run(iter); 204 if (ret) { 205 v->num_levels = 0; 206 devm_kfree(ph->dev, v->levels_uv); 207 } 208 209 return ret; 210} 211 212static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, 213 struct voltage_info *vinfo) 214{ 215 int ret, dom; 216 struct scmi_xfer *td; 217 struct scmi_msg_resp_domain_attributes *resp_dom; 218 219 ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES, 220 sizeof(__le32), sizeof(*resp_dom), &td); 221 if (ret) 222 return ret; 223 resp_dom = td->rx.buf; 224 225 for (dom = 0; dom < vinfo->num_domains; dom++) { 226 u32 attributes; 227 struct scmi_voltage_info *v; 228 229 /* Retrieve domain attributes at first ... */ 230 put_unaligned_le32(dom, td->tx.buf); 231 /* Skip domain on comms error */ 232 if (ph->xops->do_xfer(ph, td)) { 233 ph->xops->reset_rx_to_maxsz(ph, td); 234 continue; 235 } 236 237 v = vinfo->domains + dom; 238 v->id = dom; 239 attributes = le32_to_cpu(resp_dom->attr); 240 strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE); 241 242 /* 243 * If supported overwrite short name with the extended one; 244 * on error just carry on and use already provided short name. 245 */ 246 if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) { 247 if (SUPPORTS_EXTENDED_NAMES(attributes)) 248 ph->hops->extended_name_get(ph, 249 VOLTAGE_DOMAIN_NAME_GET, 250 v->id, NULL, v->name, 251 SCMI_MAX_STR_SIZE); 252 if (SUPPORTS_ASYNC_LEVEL_SET(attributes)) 253 v->async_level_set = true; 254 } 255 256 /* Skip invalid voltage descriptors */ 257 scmi_voltage_levels_get(ph, v); 258 } 259 260 ph->xops->xfer_put(ph, td); 261 262 return ret; 263} 264 265static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph, 266 u8 cmd_id, u32 domain_id, u32 *value) 267{ 268 int ret; 269 struct scmi_xfer *t; 270 struct voltage_info *vinfo = ph->get_priv(ph); 271 272 if (domain_id >= vinfo->num_domains) 273 return -EINVAL; 274 275 ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t); 276 if (ret) 277 return ret; 278 279 put_unaligned_le32(domain_id, t->tx.buf); 280 ret = ph->xops->do_xfer(ph, t); 281 if (!ret) 282 *value = get_unaligned_le32(t->rx.buf); 283 284 ph->xops->xfer_put(ph, t); 285 return ret; 286} 287 288static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph, 289 u32 domain_id, u32 config) 290{ 291 int ret; 292 struct scmi_xfer *t; 293 struct voltage_info *vinfo = ph->get_priv(ph); 294 struct scmi_msg_cmd_config_set *cmd; 295 296 if (domain_id >= vinfo->num_domains) 297 return -EINVAL; 298 299 ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET, 300 sizeof(*cmd), 0, &t); 301 if (ret) 302 return ret; 303 304 cmd = t->tx.buf; 305 cmd->domain_id = cpu_to_le32(domain_id); 306 cmd->config = cpu_to_le32(config & GENMASK(3, 0)); 307 308 ret = ph->xops->do_xfer(ph, t); 309 310 ph->xops->xfer_put(ph, t); 311 return ret; 312} 313 314static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph, 315 u32 domain_id, u32 *config) 316{ 317 return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET, 318 domain_id, config); 319} 320 321static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph, 322 u32 domain_id, 323 enum scmi_voltage_level_mode mode, 324 s32 volt_uV) 325{ 326 int ret; 327 struct scmi_xfer *t; 328 struct voltage_info *vinfo = ph->get_priv(ph); 329 struct scmi_msg_cmd_level_set *cmd; 330 struct scmi_voltage_info *v; 331 332 if (domain_id >= vinfo->num_domains) 333 return -EINVAL; 334 335 ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET, 336 sizeof(*cmd), 0, &t); 337 if (ret) 338 return ret; 339 340 v = vinfo->domains + domain_id; 341 342 cmd = t->tx.buf; 343 cmd->domain_id = cpu_to_le32(domain_id); 344 cmd->voltage_level = cpu_to_le32(volt_uV); 345 346 if (!v->async_level_set || mode != SCMI_VOLTAGE_LEVEL_SET_AUTO) { 347 cmd->flags = cpu_to_le32(0x0); 348 ret = ph->xops->do_xfer(ph, t); 349 } else { 350 cmd->flags = cpu_to_le32(0x1); 351 ret = ph->xops->do_xfer_with_response(ph, t); 352 if (!ret) { 353 struct scmi_resp_voltage_level_set_complete *resp; 354 355 resp = t->rx.buf; 356 if (le32_to_cpu(resp->domain_id) == domain_id) 357 dev_dbg(ph->dev, 358 "Voltage domain %d set async to %d\n", 359 v->id, 360 le32_to_cpu(resp->voltage_level)); 361 else 362 ret = -EPROTO; 363 } 364 } 365 366 ph->xops->xfer_put(ph, t); 367 return ret; 368} 369 370static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph, 371 u32 domain_id, s32 *volt_uV) 372{ 373 return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET, 374 domain_id, (u32 *)volt_uV); 375} 376 377static const struct scmi_voltage_info * __must_check 378scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id) 379{ 380 struct voltage_info *vinfo = ph->get_priv(ph); 381 382 if (domain_id >= vinfo->num_domains || 383 !vinfo->domains[domain_id].num_levels) 384 return NULL; 385 386 return vinfo->domains + domain_id; 387} 388 389static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph) 390{ 391 struct voltage_info *vinfo = ph->get_priv(ph); 392 393 return vinfo->num_domains; 394} 395 396static const struct scmi_voltage_proto_ops voltage_proto_ops = { 397 .num_domains_get = scmi_voltage_domains_num_get, 398 .info_get = scmi_voltage_info_get, 399 .config_set = scmi_voltage_config_set, 400 .config_get = scmi_voltage_config_get, 401 .level_set = scmi_voltage_level_set, 402 .level_get = scmi_voltage_level_get, 403}; 404 405static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph) 406{ 407 int ret; 408 u32 version; 409 struct voltage_info *vinfo; 410 411 ret = ph->xops->version_get(ph, &version); 412 if (ret) 413 return ret; 414 415 dev_dbg(ph->dev, "Voltage Version %d.%d\n", 416 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 417 418 vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL); 419 if (!vinfo) 420 return -ENOMEM; 421 vinfo->version = version; 422 423 ret = scmi_protocol_attributes_get(ph, vinfo); 424 if (ret) 425 return ret; 426 427 if (vinfo->num_domains) { 428 vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains, 429 sizeof(*vinfo->domains), 430 GFP_KERNEL); 431 if (!vinfo->domains) 432 return -ENOMEM; 433 ret = scmi_voltage_descriptors_get(ph, vinfo); 434 if (ret) 435 return ret; 436 } else { 437 dev_warn(ph->dev, "No Voltage domains found.\n"); 438 } 439 440 return ph->set_priv(ph, vinfo, version); 441} 442 443static const struct scmi_protocol scmi_voltage = { 444 .id = SCMI_PROTOCOL_VOLTAGE, 445 .owner = THIS_MODULE, 446 .instance_init = &scmi_voltage_protocol_init, 447 .ops = &voltage_proto_ops, 448 .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 449}; 450 451DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)
~/
Read-only file preview.