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