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); 309