e8839d95833104d152cd070b2a896071b66ae625
[AGL/meta-agl-devel.git] / meta-egvirt / recipes-kernel / linux / linux-yocto / scmi / 0004-firmware-arm_scmi-add-SCMIv3.0-Sensors-timestamped-r.patch
1 From bb48061a3f1edd4203518aa4b8a021ae5d1582a4 Mon Sep 17 00:00:00 2001
2 From: Cristian Marussi <cristian.marussi@arm.com>
3 Date: Thu, 19 Nov 2020 17:49:04 +0000
4 Subject: [PATCH] firmware: arm_scmi: add SCMIv3.0 Sensors timestamped reads
5
6 Add new .reading_get_timestamped() method to sensor_ops to support SCMIv3.0
7 timestamped reads.
8
9 Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
10 Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
11 ---
12  drivers/firmware/arm_scmi/sensors.c | 127 ++++++++++++++++++++++++++--
13  include/linux/scmi_protocol.h       |  22 +++++
14  2 files changed, 143 insertions(+), 6 deletions(-)
15
16 diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
17 index a85827f60a02..2239af5f9e6e 100644
18 --- a/drivers/firmware/arm_scmi/sensors.c
19 +++ b/drivers/firmware/arm_scmi/sensors.c
20 @@ -155,6 +155,23 @@ struct scmi_msg_sensor_reading_get {
21  #define SENSOR_READ_ASYNC      BIT(0)
22  };
23  
24 +struct scmi_resp_sensor_reading_complete {
25 +       __le32 id;
26 +       __le64 readings;
27 +};
28 +
29 +struct scmi_sensor_reading_le {
30 +       __le32 sensor_value_low;
31 +       __le32 sensor_value_high;
32 +       __le32 timestamp_low;
33 +       __le32 timestamp_high;
34 +};
35 +
36 +struct scmi_resp_sensor_reading_complete_v3 {
37 +       __le32 id;
38 +       struct scmi_sensor_reading_le readings[];
39 +};
40 +
41  struct scmi_sensor_trip_notify_payld {
42         __le32 agent_id;
43         __le32 sensor_id;
44 @@ -575,6 +592,21 @@ scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
45         return ret;
46  }
47  
48 +/**
49 + * scmi_sensor_reading_get  - Read scalar sensor value
50 + * @handle: Platform handle
51 + * @sensor_id: Sensor ID
52 + * @value: The 64bit value sensor reading
53 + *
54 + * This function returns a single 64 bit reading value representing the sensor
55 + * value; if the platform SCMI Protocol implementation and the sensor support
56 + * multiple axis and timestamped-reads, this just returns the first axis while
57 + * dropping the timestamp value.
58 + * Use instead the @scmi_sensor_reading_get_timestamped to retrieve the array of
59 + * timestamped multi-axis values.
60 + *
61 + * Return: 0 on Success
62 + */
63  static int scmi_sensor_reading_get(const struct scmi_handle *handle,
64                                    u32 sensor_id, u64 *value)
65  {
66 @@ -585,20 +617,24 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
67         struct scmi_sensor_info *s = si->sensors + sensor_id;
68  
69         ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
70 -                                SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
71 -                                sizeof(u64), &t);
72 +                                SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
73         if (ret)
74                 return ret;
75  
76         sensor = t->tx.buf;
77         sensor->id = cpu_to_le32(sensor_id);
78 -
79         if (s->async) {
80                 sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
81                 ret = scmi_do_xfer_with_response(handle, t);
82 -               if (!ret)
83 -                       *value = get_unaligned_le64((void *)
84 -                                                   ((__le32 *)t->rx.buf + 1));
85 +               if (!ret) {
86 +                       struct scmi_resp_sensor_reading_complete *resp;
87 +
88 +                       resp = t->rx.buf;
89 +                       if (le32_to_cpu(resp->id) == sensor_id)
90 +                               *value = get_unaligned_le64(&resp->readings);
91 +                       else
92 +                               ret = -EPROTO;
93 +               }
94         } else {
95                 sensor->flags = cpu_to_le32(0);
96                 ret = scmi_do_xfer(handle, t);
97 @@ -610,6 +646,84 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
98         return ret;
99  }
100  
101 +static inline void
102 +scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
103 +                          const struct scmi_sensor_reading_le *in)
104 +{
105 +       out->value = get_unaligned_le64((void *)&in->sensor_value_low);
106 +       out->timestamp = get_unaligned_le64((void *)&in->timestamp_low);
107 +}
108 +
109 +/**
110 + * scmi_sensor_reading_get_timestamped  - Read multiple-axis timestamped values
111 + * @handle: Platform handle
112 + * @sensor_id: Sensor ID
113 + * @count: The length of the provided @readings array
114 + * @readings: An array of elements each representing a timestamped per-axis
115 + *           reading of type @struct scmi_sensor_reading.
116 + *           Returned readings are ordered as the @axis descriptors array
117 + *           included in @struct scmi_sensor_info and the max number of
118 + *           returned elements is min(@count, @num_axis); ideally the provided
119 + *           array should be of length @count equal to @num_axis.
120 + *
121 + * Return: 0 on Success
122 + */
123 +static int
124 +scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
125 +                                   u32 sensor_id, u8 count,
126 +                                   struct scmi_sensor_reading *readings)
127 +{
128 +       int ret;
129 +       struct scmi_xfer *t;
130 +       struct scmi_msg_sensor_reading_get *sensor;
131 +       struct sensors_info *si = handle->sensor_priv;
132 +       struct scmi_sensor_info *s = si->sensors + sensor_id;
133 +
134 +       if (!count || !readings ||
135 +           (!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis))
136 +               return -EINVAL;
137 +
138 +       ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
139 +                                SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
140 +       if (ret)
141 +               return ret;
142 +
143 +       sensor = t->tx.buf;
144 +       sensor->id = cpu_to_le32(sensor_id);
145 +       if (s->async) {
146 +               sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
147 +               ret = scmi_do_xfer_with_response(handle, t);
148 +               if (!ret) {
149 +                       int i;
150 +                       struct scmi_resp_sensor_reading_complete_v3 *resp;
151 +
152 +                       resp = t->rx.buf;
153 +                       /* Retrieve only the number of requested axis anyway */
154 +                       if (le32_to_cpu(resp->id) == sensor_id)
155 +                               for (i = 0; i < count; i++)
156 +                                       scmi_parse_sensor_readings(&readings[i],
157 +                                                                  &resp->readings[i]);
158 +                       else
159 +                               ret = -EPROTO;
160 +               }
161 +       } else {
162 +               sensor->flags = cpu_to_le32(0);
163 +               ret = scmi_do_xfer(handle, t);
164 +               if (!ret) {
165 +                       int i;
166 +                       struct scmi_sensor_reading_le *resp_readings;
167 +
168 +                       resp_readings = t->rx.buf;
169 +                       for (i = 0; i < count; i++)
170 +                               scmi_parse_sensor_readings(&readings[i],
171 +                                                          &resp_readings[i]);
172 +               }
173 +       }
174 +
175 +       scmi_xfer_put(handle, t);
176 +       return ret;
177 +}
178 +
179  static const struct scmi_sensor_info *
180  scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
181  {
182 @@ -630,6 +744,7 @@ static const struct scmi_sensor_ops sensor_ops = {
183         .info_get = scmi_sensor_info_get,
184         .trip_point_config = scmi_sensor_trip_point_config,
185         .reading_get = scmi_sensor_reading_get,
186 +       .reading_get_timestamped = scmi_sensor_reading_get_timestamped,
187  };
188  
189  static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
190 diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
191 index 0792b0be25a3..0c52bf0cbee4 100644
192 --- a/include/linux/scmi_protocol.h
193 +++ b/include/linux/scmi_protocol.h
194 @@ -149,6 +149,20 @@ struct scmi_power_ops {
195                          u32 *state);
196  };
197  
198 +/**
199 + * scmi_sensor_reading  - represent a timestamped read
200 + *
201 + * Used by @reading_get_timestamped method.
202 + *
203 + * @value: The signed value sensor read.
204 + * @timestamp: An unsigned timestamp for the sensor read, as provided by
205 + *            SCMI platform. Set to zero when not available.
206 + */
207 +struct scmi_sensor_reading {
208 +       long long value;
209 +       unsigned long long timestamp;
210 +};
211 +
212  /**
213   * scmi_range_attrs  - specifies a sensor or axis values' range
214   * @min_range: The minimum value which can be represented by the sensor/axis.
215 @@ -390,6 +404,11 @@ enum scmi_sensor_class {
216   * @info_get: get the information of the specified sensor
217   * @trip_point_config: selects and configures a trip-point of interest
218   * @reading_get: gets the current value of the sensor
219 + * @reading_get_timestamped: gets the current value and timestamp, when
220 + *                          available, of the sensor. (as of v3.0 spec)
221 + *                          Supports multi-axis sensors for sensors which
222 + *                          supports it and if the @reading array size of
223 + *                          @count entry equals the sensor num_axis
224   */
225  struct scmi_sensor_ops {
226         int (*count_get)(const struct scmi_handle *handle);
227 @@ -399,6 +418,9 @@ struct scmi_sensor_ops {
228                                  u32 sensor_id, u8 trip_id, u64 trip_value);
229         int (*reading_get)(const struct scmi_handle *handle, u32 sensor_id,
230                            u64 *value);
231 +       int (*reading_get_timestamped)(const struct scmi_handle *handle,
232 +                                      u32 sensor_id, u8 count,
233 +                                      struct scmi_sensor_reading *readings);
234  };
235  
236  /**