Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * System Control and Management Interface (SCMI) Voltage Protocol
0004  *
0005  * Copyright (C) 2020-2022 ARM Ltd.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/scmi_protocol.h>
0010 
0011 #include "protocols.h"
0012 
0013 #define VOLTAGE_DOMS_NUM_MASK       GENMASK(15, 0)
0014 #define REMAINING_LEVELS_MASK       GENMASK(31, 16)
0015 #define RETURNED_LEVELS_MASK        GENMASK(11, 0)
0016 
0017 enum scmi_voltage_protocol_cmd {
0018     VOLTAGE_DOMAIN_ATTRIBUTES = 0x3,
0019     VOLTAGE_DESCRIBE_LEVELS = 0x4,
0020     VOLTAGE_CONFIG_SET = 0x5,
0021     VOLTAGE_CONFIG_GET = 0x6,
0022     VOLTAGE_LEVEL_SET = 0x7,
0023     VOLTAGE_LEVEL_GET = 0x8,
0024     VOLTAGE_DOMAIN_NAME_GET = 0x09,
0025 };
0026 
0027 #define NUM_VOLTAGE_DOMAINS(x)  ((u16)(FIELD_GET(VOLTAGE_DOMS_NUM_MASK, (x))))
0028 
0029 struct scmi_msg_resp_domain_attributes {
0030     __le32 attr;
0031 #define SUPPORTS_ASYNC_LEVEL_SET(x) ((x) & BIT(31))
0032 #define SUPPORTS_EXTENDED_NAMES(x)  ((x) & BIT(30))
0033     u8 name[SCMI_SHORT_NAME_MAX_SIZE];
0034 };
0035 
0036 struct scmi_msg_cmd_describe_levels {
0037     __le32 domain_id;
0038     __le32 level_index;
0039 };
0040 
0041 struct scmi_msg_resp_describe_levels {
0042     __le32 flags;
0043 #define NUM_REMAINING_LEVELS(f) ((u16)(FIELD_GET(REMAINING_LEVELS_MASK, (f))))
0044 #define NUM_RETURNED_LEVELS(f)  ((u16)(FIELD_GET(RETURNED_LEVELS_MASK, (f))))
0045 #define SUPPORTS_SEGMENTED_LEVELS(f)    ((f) & BIT(12))
0046     __le32 voltage[];
0047 };
0048 
0049 struct scmi_msg_cmd_config_set {
0050     __le32 domain_id;
0051     __le32 config;
0052 };
0053 
0054 struct scmi_msg_cmd_level_set {
0055     __le32 domain_id;
0056     __le32 flags;
0057     __le32 voltage_level;
0058 };
0059 
0060 struct scmi_resp_voltage_level_set_complete {
0061     __le32 domain_id;
0062     __le32 voltage_level;
0063 };
0064 
0065 struct voltage_info {
0066     unsigned int version;
0067     unsigned int num_domains;
0068     struct scmi_voltage_info *domains;
0069 };
0070 
0071 static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph,
0072                     struct voltage_info *vinfo)
0073 {
0074     int ret;
0075     struct scmi_xfer *t;
0076 
0077     ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
0078                       sizeof(__le32), &t);
0079     if (ret)
0080         return ret;
0081 
0082     ret = ph->xops->do_xfer(ph, t);
0083     if (!ret)
0084         vinfo->num_domains =
0085             NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf));
0086 
0087     ph->xops->xfer_put(ph, t);
0088     return ret;
0089 }
0090 
0091 static int scmi_init_voltage_levels(struct device *dev,
0092                     struct scmi_voltage_info *v,
0093                     u32 num_returned, u32 num_remaining,
0094                     bool segmented)
0095 {
0096     u32 num_levels;
0097 
0098     num_levels = num_returned + num_remaining;
0099     /*
0100      * segmented levels entries are represented by a single triplet
0101      * returned all in one go.
0102      */
0103     if (!num_levels ||
0104         (segmented && (num_remaining || num_returned != 3))) {
0105         dev_err(dev,
0106             "Invalid level descriptor(%d/%d/%d) for voltage dom %d\n",
0107             num_levels, num_returned, num_remaining, v->id);
0108         return -EINVAL;
0109     }
0110 
0111     v->levels_uv = devm_kcalloc(dev, num_levels, sizeof(u32), GFP_KERNEL);
0112     if (!v->levels_uv)
0113         return -ENOMEM;
0114 
0115     v->num_levels = num_levels;
0116     v->segmented = segmented;
0117 
0118     return 0;
0119 }
0120 
0121 struct scmi_volt_ipriv {
0122     struct device *dev;
0123     struct scmi_voltage_info *v;
0124 };
0125 
0126 static void iter_volt_levels_prepare_message(void *message,
0127                          unsigned int desc_index,
0128                          const void *priv)
0129 {
0130     struct scmi_msg_cmd_describe_levels *msg = message;
0131     const struct scmi_volt_ipriv *p = priv;
0132 
0133     msg->domain_id = cpu_to_le32(p->v->id);
0134     msg->level_index = cpu_to_le32(desc_index);
0135 }
0136 
0137 static int iter_volt_levels_update_state(struct scmi_iterator_state *st,
0138                      const void *response, void *priv)
0139 {
0140     int ret = 0;
0141     u32 flags;
0142     const struct scmi_msg_resp_describe_levels *r = response;
0143     struct scmi_volt_ipriv *p = priv;
0144 
0145     flags = le32_to_cpu(r->flags);
0146     st->num_returned = NUM_RETURNED_LEVELS(flags);
0147     st->num_remaining = NUM_REMAINING_LEVELS(flags);
0148 
0149     /* Allocate space for num_levels if not already done */
0150     if (!p->v->num_levels) {
0151         ret = scmi_init_voltage_levels(p->dev, p->v, st->num_returned,
0152                            st->num_remaining,
0153                           SUPPORTS_SEGMENTED_LEVELS(flags));
0154         if (!ret)
0155             st->max_resources = p->v->num_levels;
0156     }
0157 
0158     return ret;
0159 }
0160 
0161 static int
0162 iter_volt_levels_process_response(const struct scmi_protocol_handle *ph,
0163                   const void *response,
0164                   struct scmi_iterator_state *st, void *priv)
0165 {
0166     s32 val;
0167     const struct scmi_msg_resp_describe_levels *r = response;
0168     struct scmi_volt_ipriv *p = priv;
0169 
0170     val = (s32)le32_to_cpu(r->voltage[st->loop_idx]);
0171     p->v->levels_uv[st->desc_index + st->loop_idx] = val;
0172     if (val < 0)
0173         p->v->negative_volts_allowed = true;
0174 
0175     return 0;
0176 }
0177 
0178 static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
0179                    struct scmi_voltage_info *v)
0180 {
0181     int ret;
0182     void *iter;
0183     struct scmi_iterator_ops ops = {
0184         .prepare_message = iter_volt_levels_prepare_message,
0185         .update_state = iter_volt_levels_update_state,
0186         .process_response = iter_volt_levels_process_response,
0187     };
0188     struct scmi_volt_ipriv vpriv = {
0189         .dev = ph->dev,
0190         .v = v,
0191     };
0192 
0193     iter = ph->hops->iter_response_init(ph, &ops, v->num_levels,
0194                         VOLTAGE_DESCRIBE_LEVELS,
0195                         sizeof(struct scmi_msg_cmd_describe_levels),
0196                         &vpriv);
0197     if (IS_ERR(iter))
0198         return PTR_ERR(iter);
0199 
0200     ret = ph->hops->iter_response_run(iter);
0201     if (ret) {
0202         v->num_levels = 0;
0203         devm_kfree(ph->dev, v->levels_uv);
0204     }
0205 
0206     return ret;
0207 }
0208 
0209 static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
0210                     struct voltage_info *vinfo)
0211 {
0212     int ret, dom;
0213     struct scmi_xfer *td;
0214     struct scmi_msg_resp_domain_attributes *resp_dom;
0215 
0216     ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES,
0217                       sizeof(__le32), sizeof(*resp_dom), &td);
0218     if (ret)
0219         return ret;
0220     resp_dom = td->rx.buf;
0221 
0222     for (dom = 0; dom < vinfo->num_domains; dom++) {
0223         u32 attributes;
0224         struct scmi_voltage_info *v;
0225 
0226         /* Retrieve domain attributes at first ... */
0227         put_unaligned_le32(dom, td->tx.buf);
0228         /* Skip domain on comms error */
0229         if (ph->xops->do_xfer(ph, td))
0230             continue;
0231 
0232         v = vinfo->domains + dom;
0233         v->id = dom;
0234         attributes = le32_to_cpu(resp_dom->attr);
0235         strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE);
0236 
0237         /*
0238          * If supported overwrite short name with the extended one;
0239          * on error just carry on and use already provided short name.
0240          */
0241         if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
0242             if (SUPPORTS_EXTENDED_NAMES(attributes))
0243                 ph->hops->extended_name_get(ph,
0244                             VOLTAGE_DOMAIN_NAME_GET,
0245                             v->id, v->name,
0246                             SCMI_MAX_STR_SIZE);
0247             if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
0248                 v->async_level_set = true;
0249         }
0250 
0251         /* Skip invalid voltage descriptors */
0252         scmi_voltage_levels_get(ph, v);
0253     }
0254 
0255     ph->xops->xfer_put(ph, td);
0256 
0257     return ret;
0258 }
0259 
0260 static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph,
0261                   u8 cmd_id, u32 domain_id, u32 *value)
0262 {
0263     int ret;
0264     struct scmi_xfer *t;
0265     struct voltage_info *vinfo = ph->get_priv(ph);
0266 
0267     if (domain_id >= vinfo->num_domains)
0268         return -EINVAL;
0269 
0270     ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t);
0271     if (ret)
0272         return ret;
0273 
0274     put_unaligned_le32(domain_id, t->tx.buf);
0275     ret = ph->xops->do_xfer(ph, t);
0276     if (!ret)
0277         *value = get_unaligned_le32(t->rx.buf);
0278 
0279     ph->xops->xfer_put(ph, t);
0280     return ret;
0281 }
0282 
0283 static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph,
0284                    u32 domain_id, u32 config)
0285 {
0286     int ret;
0287     struct scmi_xfer *t;
0288     struct voltage_info *vinfo = ph->get_priv(ph);
0289     struct scmi_msg_cmd_config_set *cmd;
0290 
0291     if (domain_id >= vinfo->num_domains)
0292         return -EINVAL;
0293 
0294     ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET,
0295                      sizeof(*cmd), 0, &t);
0296     if (ret)
0297         return ret;
0298 
0299     cmd = t->tx.buf;
0300     cmd->domain_id = cpu_to_le32(domain_id);
0301     cmd->config = cpu_to_le32(config & GENMASK(3, 0));
0302 
0303     ret = ph->xops->do_xfer(ph, t);
0304 
0305     ph->xops->xfer_put(ph, t);
0306     return ret;
0307 }
0308 
0309 static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
0310                    u32 domain_id, u32 *config)
0311 {
0312     return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET,
0313                       domain_id, config);
0314 }
0315 
0316 static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
0317                   u32 domain_id,
0318                   enum scmi_voltage_level_mode mode,
0319                   s32 volt_uV)
0320 {
0321     int ret;
0322     struct scmi_xfer *t;
0323     struct voltage_info *vinfo = ph->get_priv(ph);
0324     struct scmi_msg_cmd_level_set *cmd;
0325     struct scmi_voltage_info *v;
0326 
0327     if (domain_id >= vinfo->num_domains)
0328         return -EINVAL;
0329 
0330     ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET,
0331                       sizeof(*cmd), 0, &t);
0332     if (ret)
0333         return ret;
0334 
0335     v = vinfo->domains + domain_id;
0336 
0337     cmd = t->tx.buf;
0338     cmd->domain_id = cpu_to_le32(domain_id);
0339     cmd->voltage_level = cpu_to_le32(volt_uV);
0340 
0341     if (!v->async_level_set || mode != SCMI_VOLTAGE_LEVEL_SET_AUTO) {
0342         cmd->flags = cpu_to_le32(0x0);
0343         ret = ph->xops->do_xfer(ph, t);
0344     } else {
0345         cmd->flags = cpu_to_le32(0x1);
0346         ret = ph->xops->do_xfer_with_response(ph, t);
0347         if (!ret) {
0348             struct scmi_resp_voltage_level_set_complete *resp;
0349 
0350             resp = t->rx.buf;
0351             if (le32_to_cpu(resp->domain_id) == domain_id)
0352                 dev_dbg(ph->dev,
0353                     "Voltage domain %d set async to %d\n",
0354                     v->id,
0355                     le32_to_cpu(resp->voltage_level));
0356             else
0357                 ret = -EPROTO;
0358         }
0359     }
0360 
0361     ph->xops->xfer_put(ph, t);
0362     return ret;
0363 }
0364 
0365 static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
0366                   u32 domain_id, s32 *volt_uV)
0367 {
0368     return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET,
0369                       domain_id, (u32 *)volt_uV);
0370 }
0371 
0372 static const struct scmi_voltage_info * __must_check
0373 scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
0374 {
0375     struct voltage_info *vinfo = ph->get_priv(ph);
0376 
0377     if (domain_id >= vinfo->num_domains ||
0378         !vinfo->domains[domain_id].num_levels)
0379         return NULL;
0380 
0381     return vinfo->domains + domain_id;
0382 }
0383 
0384 static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
0385 {
0386     struct voltage_info *vinfo = ph->get_priv(ph);
0387 
0388     return vinfo->num_domains;
0389 }
0390 
0391 static struct scmi_voltage_proto_ops voltage_proto_ops = {
0392     .num_domains_get = scmi_voltage_domains_num_get,
0393     .info_get = scmi_voltage_info_get,
0394     .config_set = scmi_voltage_config_set,
0395     .config_get = scmi_voltage_config_get,
0396     .level_set = scmi_voltage_level_set,
0397     .level_get = scmi_voltage_level_get,
0398 };
0399 
0400 static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
0401 {
0402     int ret;
0403     u32 version;
0404     struct voltage_info *vinfo;
0405 
0406     ret = ph->xops->version_get(ph, &version);
0407     if (ret)
0408         return ret;
0409 
0410     dev_dbg(ph->dev, "Voltage Version %d.%d\n",
0411         PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
0412 
0413     vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
0414     if (!vinfo)
0415         return -ENOMEM;
0416     vinfo->version = version;
0417 
0418     ret = scmi_protocol_attributes_get(ph, vinfo);
0419     if (ret)
0420         return ret;
0421 
0422     if (vinfo->num_domains) {
0423         vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains,
0424                           sizeof(*vinfo->domains),
0425                           GFP_KERNEL);
0426         if (!vinfo->domains)
0427             return -ENOMEM;
0428         ret = scmi_voltage_descriptors_get(ph, vinfo);
0429         if (ret)
0430             return ret;
0431     } else {
0432         dev_warn(ph->dev, "No Voltage domains found.\n");
0433     }
0434 
0435     return ph->set_priv(ph, vinfo);
0436 }
0437 
0438 static const struct scmi_protocol scmi_voltage = {
0439     .id = SCMI_PROTOCOL_VOLTAGE,
0440     .owner = THIS_MODULE,
0441     .instance_init = &scmi_voltage_protocol_init,
0442     .ops = &voltage_proto_ops,
0443 };
0444 
0445 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)