linux/drivers/firmware/arm_scmi/voltage.c
<<
>>
Prefs
   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)
 446