root/drivers/firmware/arm_scmi/power.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scmi_power_attributes_get
  2. scmi_power_domain_attributes_get
  3. scmi_power_state_set
  4. scmi_power_state_get
  5. scmi_power_num_domains_get
  6. scmi_power_name_get
  7. scmi_power_protocol_init
  8. scmi_power_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * System Control and Management Interface (SCMI) Power Protocol
   4  *
   5  * Copyright (C) 2018 ARM Ltd.
   6  */
   7 
   8 #include "common.h"
   9 
  10 enum scmi_power_protocol_cmd {
  11         POWER_DOMAIN_ATTRIBUTES = 0x3,
  12         POWER_STATE_SET = 0x4,
  13         POWER_STATE_GET = 0x5,
  14         POWER_STATE_NOTIFY = 0x6,
  15 };
  16 
  17 struct scmi_msg_resp_power_attributes {
  18         __le16 num_domains;
  19         __le16 reserved;
  20         __le32 stats_addr_low;
  21         __le32 stats_addr_high;
  22         __le32 stats_size;
  23 };
  24 
  25 struct scmi_msg_resp_power_domain_attributes {
  26         __le32 flags;
  27 #define SUPPORTS_STATE_SET_NOTIFY(x)    ((x) & BIT(31))
  28 #define SUPPORTS_STATE_SET_ASYNC(x)     ((x) & BIT(30))
  29 #define SUPPORTS_STATE_SET_SYNC(x)      ((x) & BIT(29))
  30             u8 name[SCMI_MAX_STR_SIZE];
  31 };
  32 
  33 struct scmi_power_set_state {
  34         __le32 flags;
  35 #define STATE_SET_ASYNC         BIT(0)
  36         __le32 domain;
  37         __le32 state;
  38 };
  39 
  40 struct scmi_power_state_notify {
  41         __le32 domain;
  42         __le32 notify_enable;
  43 };
  44 
  45 struct power_dom_info {
  46         bool state_set_sync;
  47         bool state_set_async;
  48         bool state_set_notify;
  49         char name[SCMI_MAX_STR_SIZE];
  50 };
  51 
  52 struct scmi_power_info {
  53         int num_domains;
  54         u64 stats_addr;
  55         u32 stats_size;
  56         struct power_dom_info *dom_info;
  57 };
  58 
  59 static int scmi_power_attributes_get(const struct scmi_handle *handle,
  60                                      struct scmi_power_info *pi)
  61 {
  62         int ret;
  63         struct scmi_xfer *t;
  64         struct scmi_msg_resp_power_attributes *attr;
  65 
  66         ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
  67                                  SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t);
  68         if (ret)
  69                 return ret;
  70 
  71         attr = t->rx.buf;
  72 
  73         ret = scmi_do_xfer(handle, t);
  74         if (!ret) {
  75                 pi->num_domains = le16_to_cpu(attr->num_domains);
  76                 pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
  77                                 (u64)le32_to_cpu(attr->stats_addr_high) << 32;
  78                 pi->stats_size = le32_to_cpu(attr->stats_size);
  79         }
  80 
  81         scmi_xfer_put(handle, t);
  82         return ret;
  83 }
  84 
  85 static int
  86 scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
  87                                  struct power_dom_info *dom_info)
  88 {
  89         int ret;
  90         struct scmi_xfer *t;
  91         struct scmi_msg_resp_power_domain_attributes *attr;
  92 
  93         ret = scmi_xfer_get_init(handle, POWER_DOMAIN_ATTRIBUTES,
  94                                  SCMI_PROTOCOL_POWER, sizeof(domain),
  95                                  sizeof(*attr), &t);
  96         if (ret)
  97                 return ret;
  98 
  99         put_unaligned_le32(domain, t->tx.buf);
 100         attr = t->rx.buf;
 101 
 102         ret = scmi_do_xfer(handle, t);
 103         if (!ret) {
 104                 u32 flags = le32_to_cpu(attr->flags);
 105 
 106                 dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
 107                 dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
 108                 dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
 109                 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
 110         }
 111 
 112         scmi_xfer_put(handle, t);
 113         return ret;
 114 }
 115 
 116 static int
 117 scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state)
 118 {
 119         int ret;
 120         struct scmi_xfer *t;
 121         struct scmi_power_set_state *st;
 122 
 123         ret = scmi_xfer_get_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER,
 124                                  sizeof(*st), 0, &t);
 125         if (ret)
 126                 return ret;
 127 
 128         st = t->tx.buf;
 129         st->flags = cpu_to_le32(0);
 130         st->domain = cpu_to_le32(domain);
 131         st->state = cpu_to_le32(state);
 132 
 133         ret = scmi_do_xfer(handle, t);
 134 
 135         scmi_xfer_put(handle, t);
 136         return ret;
 137 }
 138 
 139 static int
 140 scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state)
 141 {
 142         int ret;
 143         struct scmi_xfer *t;
 144 
 145         ret = scmi_xfer_get_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER,
 146                                  sizeof(u32), sizeof(u32), &t);
 147         if (ret)
 148                 return ret;
 149 
 150         put_unaligned_le32(domain, t->tx.buf);
 151 
 152         ret = scmi_do_xfer(handle, t);
 153         if (!ret)
 154                 *state = get_unaligned_le32(t->rx.buf);
 155 
 156         scmi_xfer_put(handle, t);
 157         return ret;
 158 }
 159 
 160 static int scmi_power_num_domains_get(const struct scmi_handle *handle)
 161 {
 162         struct scmi_power_info *pi = handle->power_priv;
 163 
 164         return pi->num_domains;
 165 }
 166 
 167 static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
 168 {
 169         struct scmi_power_info *pi = handle->power_priv;
 170         struct power_dom_info *dom = pi->dom_info + domain;
 171 
 172         return dom->name;
 173 }
 174 
 175 static struct scmi_power_ops power_ops = {
 176         .num_domains_get = scmi_power_num_domains_get,
 177         .name_get = scmi_power_name_get,
 178         .state_set = scmi_power_state_set,
 179         .state_get = scmi_power_state_get,
 180 };
 181 
 182 static int scmi_power_protocol_init(struct scmi_handle *handle)
 183 {
 184         int domain;
 185         u32 version;
 186         struct scmi_power_info *pinfo;
 187 
 188         scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version);
 189 
 190         dev_dbg(handle->dev, "Power Version %d.%d\n",
 191                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
 192 
 193         pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
 194         if (!pinfo)
 195                 return -ENOMEM;
 196 
 197         scmi_power_attributes_get(handle, pinfo);
 198 
 199         pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
 200                                        sizeof(*pinfo->dom_info), GFP_KERNEL);
 201         if (!pinfo->dom_info)
 202                 return -ENOMEM;
 203 
 204         for (domain = 0; domain < pinfo->num_domains; domain++) {
 205                 struct power_dom_info *dom = pinfo->dom_info + domain;
 206 
 207                 scmi_power_domain_attributes_get(handle, domain, dom);
 208         }
 209 
 210         handle->power_ops = &power_ops;
 211         handle->power_priv = pinfo;
 212 
 213         return 0;
 214 }
 215 
 216 static int __init scmi_power_init(void)
 217 {
 218         return scmi_protocol_register(SCMI_PROTOCOL_POWER,
 219                                       &scmi_power_protocol_init);
 220 }
 221 subsys_initcall(scmi_power_init);

/* [<][>][^][v][top][bottom][index][help] */