root/drivers/firmware/arm_scmi/sensors.c

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

DEFINITIONS

This source file includes following definitions.
  1. scmi_sensor_attributes_get
  2. scmi_sensor_description_get
  3. scmi_sensor_trip_point_notify
  4. scmi_sensor_trip_point_config
  5. scmi_sensor_reading_get
  6. scmi_sensor_info_get
  7. scmi_sensor_count_get
  8. scmi_sensors_protocol_init
  9. scmi_sensors_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * System Control and Management Interface (SCMI) Sensor Protocol
   4  *
   5  * Copyright (C) 2018 ARM Ltd.
   6  */
   7 
   8 #include "common.h"
   9 
  10 enum scmi_sensor_protocol_cmd {
  11         SENSOR_DESCRIPTION_GET = 0x3,
  12         SENSOR_TRIP_POINT_NOTIFY = 0x4,
  13         SENSOR_TRIP_POINT_CONFIG = 0x5,
  14         SENSOR_READING_GET = 0x6,
  15 };
  16 
  17 struct scmi_msg_resp_sensor_attributes {
  18         __le16 num_sensors;
  19         u8 max_requests;
  20         u8 reserved;
  21         __le32 reg_addr_low;
  22         __le32 reg_addr_high;
  23         __le32 reg_size;
  24 };
  25 
  26 struct scmi_msg_resp_sensor_description {
  27         __le16 num_returned;
  28         __le16 num_remaining;
  29         struct {
  30                 __le32 id;
  31                 __le32 attributes_low;
  32 #define SUPPORTS_ASYNC_READ(x)  ((x) & BIT(31))
  33 #define NUM_TRIP_POINTS(x)      ((x) & 0xff)
  34                 __le32 attributes_high;
  35 #define SENSOR_TYPE(x)          ((x) & 0xff)
  36 #define SENSOR_SCALE(x)         (((x) >> 11) & 0x1f)
  37 #define SENSOR_SCALE_SIGN       BIT(4)
  38 #define SENSOR_SCALE_EXTEND     GENMASK(7, 5)
  39 #define SENSOR_UPDATE_SCALE(x)  (((x) >> 22) & 0x1f)
  40 #define SENSOR_UPDATE_BASE(x)   (((x) >> 27) & 0x1f)
  41                     u8 name[SCMI_MAX_STR_SIZE];
  42         } desc[0];
  43 };
  44 
  45 struct scmi_msg_sensor_trip_point_notify {
  46         __le32 id;
  47         __le32 event_control;
  48 #define SENSOR_TP_NOTIFY_ALL    BIT(0)
  49 };
  50 
  51 struct scmi_msg_set_sensor_trip_point {
  52         __le32 id;
  53         __le32 event_control;
  54 #define SENSOR_TP_EVENT_MASK    (0x3)
  55 #define SENSOR_TP_DISABLED      0x0
  56 #define SENSOR_TP_POSITIVE      0x1
  57 #define SENSOR_TP_NEGATIVE      0x2
  58 #define SENSOR_TP_BOTH          0x3
  59 #define SENSOR_TP_ID(x)         (((x) & 0xff) << 4)
  60         __le32 value_low;
  61         __le32 value_high;
  62 };
  63 
  64 struct scmi_msg_sensor_reading_get {
  65         __le32 id;
  66         __le32 flags;
  67 #define SENSOR_READ_ASYNC       BIT(0)
  68 };
  69 
  70 struct sensors_info {
  71         int num_sensors;
  72         int max_requests;
  73         u64 reg_addr;
  74         u32 reg_size;
  75         struct scmi_sensor_info *sensors;
  76 };
  77 
  78 static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
  79                                       struct sensors_info *si)
  80 {
  81         int ret;
  82         struct scmi_xfer *t;
  83         struct scmi_msg_resp_sensor_attributes *attr;
  84 
  85         ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
  86                                  SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t);
  87         if (ret)
  88                 return ret;
  89 
  90         attr = t->rx.buf;
  91 
  92         ret = scmi_do_xfer(handle, t);
  93         if (!ret) {
  94                 si->num_sensors = le16_to_cpu(attr->num_sensors);
  95                 si->max_requests = attr->max_requests;
  96                 si->reg_addr = le32_to_cpu(attr->reg_addr_low) |
  97                                 (u64)le32_to_cpu(attr->reg_addr_high) << 32;
  98                 si->reg_size = le32_to_cpu(attr->reg_size);
  99         }
 100 
 101         scmi_xfer_put(handle, t);
 102         return ret;
 103 }
 104 
 105 static int scmi_sensor_description_get(const struct scmi_handle *handle,
 106                                        struct sensors_info *si)
 107 {
 108         int ret, cnt;
 109         u32 desc_index = 0;
 110         u16 num_returned, num_remaining;
 111         struct scmi_xfer *t;
 112         struct scmi_msg_resp_sensor_description *buf;
 113 
 114         ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET,
 115                                  SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t);
 116         if (ret)
 117                 return ret;
 118 
 119         buf = t->rx.buf;
 120 
 121         do {
 122                 /* Set the number of sensors to be skipped/already read */
 123                 put_unaligned_le32(desc_index, t->tx.buf);
 124 
 125                 ret = scmi_do_xfer(handle, t);
 126                 if (ret)
 127                         break;
 128 
 129                 num_returned = le16_to_cpu(buf->num_returned);
 130                 num_remaining = le16_to_cpu(buf->num_remaining);
 131 
 132                 if (desc_index + num_returned > si->num_sensors) {
 133                         dev_err(handle->dev, "No. of sensors can't exceed %d",
 134                                 si->num_sensors);
 135                         break;
 136                 }
 137 
 138                 for (cnt = 0; cnt < num_returned; cnt++) {
 139                         u32 attrh, attrl;
 140                         struct scmi_sensor_info *s;
 141 
 142                         attrl = le32_to_cpu(buf->desc[cnt].attributes_low);
 143                         attrh = le32_to_cpu(buf->desc[cnt].attributes_high);
 144                         s = &si->sensors[desc_index + cnt];
 145                         s->id = le32_to_cpu(buf->desc[cnt].id);
 146                         s->type = SENSOR_TYPE(attrh);
 147                         s->scale = SENSOR_SCALE(attrh);
 148                         /* Sign extend to a full s8 */
 149                         if (s->scale & SENSOR_SCALE_SIGN)
 150                                 s->scale |= SENSOR_SCALE_EXTEND;
 151                         s->async = SUPPORTS_ASYNC_READ(attrl);
 152                         s->num_trip_points = NUM_TRIP_POINTS(attrl);
 153                         strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
 154                 }
 155 
 156                 desc_index += num_returned;
 157                 /*
 158                  * check for both returned and remaining to avoid infinite
 159                  * loop due to buggy firmware
 160                  */
 161         } while (num_returned && num_remaining);
 162 
 163         scmi_xfer_put(handle, t);
 164         return ret;
 165 }
 166 
 167 static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
 168                                          u32 sensor_id, bool enable)
 169 {
 170         int ret;
 171         u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0;
 172         struct scmi_xfer *t;
 173         struct scmi_msg_sensor_trip_point_notify *cfg;
 174 
 175         ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY,
 176                                  SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
 177         if (ret)
 178                 return ret;
 179 
 180         cfg = t->tx.buf;
 181         cfg->id = cpu_to_le32(sensor_id);
 182         cfg->event_control = cpu_to_le32(evt_cntl);
 183 
 184         ret = scmi_do_xfer(handle, t);
 185 
 186         scmi_xfer_put(handle, t);
 187         return ret;
 188 }
 189 
 190 static int
 191 scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
 192                               u8 trip_id, u64 trip_value)
 193 {
 194         int ret;
 195         u32 evt_cntl = SENSOR_TP_BOTH;
 196         struct scmi_xfer *t;
 197         struct scmi_msg_set_sensor_trip_point *trip;
 198 
 199         ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG,
 200                                  SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t);
 201         if (ret)
 202                 return ret;
 203 
 204         trip = t->tx.buf;
 205         trip->id = cpu_to_le32(sensor_id);
 206         trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id));
 207         trip->value_low = cpu_to_le32(trip_value & 0xffffffff);
 208         trip->value_high = cpu_to_le32(trip_value >> 32);
 209 
 210         ret = scmi_do_xfer(handle, t);
 211 
 212         scmi_xfer_put(handle, t);
 213         return ret;
 214 }
 215 
 216 static int scmi_sensor_reading_get(const struct scmi_handle *handle,
 217                                    u32 sensor_id, u64 *value)
 218 {
 219         int ret;
 220         struct scmi_xfer *t;
 221         struct scmi_msg_sensor_reading_get *sensor;
 222         struct sensors_info *si = handle->sensor_priv;
 223         struct scmi_sensor_info *s = si->sensors + sensor_id;
 224 
 225         ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
 226                                  SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
 227                                  sizeof(u64), &t);
 228         if (ret)
 229                 return ret;
 230 
 231         sensor = t->tx.buf;
 232         sensor->id = cpu_to_le32(sensor_id);
 233 
 234         if (s->async) {
 235                 sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
 236                 ret = scmi_do_xfer_with_response(handle, t);
 237                 if (!ret)
 238                         *value = get_unaligned_le64((void *)
 239                                                     ((__le32 *)t->rx.buf + 1));
 240         } else {
 241                 sensor->flags = cpu_to_le32(0);
 242                 ret = scmi_do_xfer(handle, t);
 243                 if (!ret)
 244                         *value = get_unaligned_le64(t->rx.buf);
 245         }
 246 
 247         scmi_xfer_put(handle, t);
 248         return ret;
 249 }
 250 
 251 static const struct scmi_sensor_info *
 252 scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
 253 {
 254         struct sensors_info *si = handle->sensor_priv;
 255 
 256         return si->sensors + sensor_id;
 257 }
 258 
 259 static int scmi_sensor_count_get(const struct scmi_handle *handle)
 260 {
 261         struct sensors_info *si = handle->sensor_priv;
 262 
 263         return si->num_sensors;
 264 }
 265 
 266 static struct scmi_sensor_ops sensor_ops = {
 267         .count_get = scmi_sensor_count_get,
 268         .info_get = scmi_sensor_info_get,
 269         .trip_point_notify = scmi_sensor_trip_point_notify,
 270         .trip_point_config = scmi_sensor_trip_point_config,
 271         .reading_get = scmi_sensor_reading_get,
 272 };
 273 
 274 static int scmi_sensors_protocol_init(struct scmi_handle *handle)
 275 {
 276         u32 version;
 277         struct sensors_info *sinfo;
 278 
 279         scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version);
 280 
 281         dev_dbg(handle->dev, "Sensor Version %d.%d\n",
 282                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
 283 
 284         sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL);
 285         if (!sinfo)
 286                 return -ENOMEM;
 287 
 288         scmi_sensor_attributes_get(handle, sinfo);
 289 
 290         sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors,
 291                                       sizeof(*sinfo->sensors), GFP_KERNEL);
 292         if (!sinfo->sensors)
 293                 return -ENOMEM;
 294 
 295         scmi_sensor_description_get(handle, sinfo);
 296 
 297         handle->sensor_ops = &sensor_ops;
 298         handle->sensor_priv = sinfo;
 299 
 300         return 0;
 301 }
 302 
 303 static int __init scmi_sensors_init(void)
 304 {
 305         return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
 306                                       &scmi_sensors_protocol_init);
 307 }
 308 subsys_initcall(scmi_sensors_init);

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