1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "sensor.h"
9 
10 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
11 #    include <mod_scmi_sensor.h>
12 #endif
13 #include <mod_sensor.h>
14 
15 #include <fwk_assert.h>
16 #include <fwk_core.h>
17 #include <fwk_event.h>
18 #include <fwk_id.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 #include <fwk_status.h>
23 #include <fwk_string.h>
24 
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 
29 static struct sensor_dev_ctx *ctx_table;
30 static struct mod_sensor_ctx sensor_mod_ctx;
31 
sensor_get_ctx(fwk_id_t id)32 struct sensor_dev_ctx *sensor_get_ctx(fwk_id_t id)
33 {
34     return ctx_table + fwk_id_get_element_idx(id);
35 }
36 
get_ctx_if_valid_call(fwk_id_t id,void * data,struct sensor_dev_ctx ** ctx)37 static int get_ctx_if_valid_call(fwk_id_t id,
38                                  void *data,
39                                  struct sensor_dev_ctx **ctx)
40 {
41     fwk_assert(ctx != NULL);
42 
43     if (!fwk_expect(data != NULL)) {
44         return FWK_E_PARAM;
45     }
46 
47     *ctx = ctx_table + fwk_id_get_element_idx(id);
48 
49     return FWK_SUCCESS;
50 }
51 
sensor_data_copy(struct mod_sensor_data * dest,const struct mod_sensor_data * origin)52 static inline void sensor_data_copy(
53     struct mod_sensor_data *dest,
54     const struct mod_sensor_data *origin)
55 {
56 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
57     mod_sensor_value_t *value = dest->axis_value;
58 #endif
59 
60     fwk_str_memcpy(dest, origin, sizeof(struct mod_sensor_data));
61 
62 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
63     if (dest->axis_count > 1) {
64         dest->axis_value = value;
65         fwk_str_memcpy(
66             dest->axis_value,
67             origin->axis_value,
68             sizeof(uint64_t) * dest->axis_count);
69     }
70 #endif
71 }
72 
73 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
trip_point_evaluate(struct sensor_trip_point_ctx * ctx,uint64_t value)74 static bool trip_point_evaluate(
75     struct sensor_trip_point_ctx *ctx,
76     uint64_t value)
77 {
78     uint64_t threshold;
79     bool new_above_threshold, trigger = false;
80 
81     threshold = ctx->params.tp_value;
82     new_above_threshold = value > threshold;
83 
84     switch (ctx->params.mode) {
85     case MOD_SENSOR_TRIP_POINT_MODE_POSITIVE:
86         if (!ctx->above_threshold && value > threshold)
87             trigger = true;
88         break;
89 
90     case MOD_SENSOR_TRIP_POINT_MODE_NEGATIVE:
91         if (ctx->above_threshold && (value <= threshold))
92             trigger = true;
93         break;
94 
95     case MOD_SENSOR_TRIP_POINT_MODE_TRANSITION:
96         if ((!ctx->above_threshold && value > threshold) ||
97             (ctx->above_threshold && value <= threshold))
98             trigger = true;
99         break;
100 
101     default:
102         break;
103     }
104 
105     ctx->above_threshold = new_above_threshold;
106     return trigger;
107 }
108 #endif
109 
110 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
trip_point_process(fwk_id_t id,struct mod_sensor_data * data)111 static void trip_point_process(fwk_id_t id, struct mod_sensor_data *data)
112 {
113     struct sensor_dev_ctx *ctx;
114     unsigned int i;
115 
116     fwk_check(!fwk_id_is_equal(id, FWK_ID_NONE));
117     ctx = ctx_table + fwk_id_get_element_idx(id);
118 
119     if (!ctx->trip_point_ctx->enabled) {
120         return;
121     }
122 
123     for (i = 0; i < ctx->config->trip_point.count; i++) {
124         if (trip_point_evaluate(&(ctx->trip_point_ctx[i]), data->value)) {
125             /* Handle trip point event*/
126             if (sensor_mod_ctx.sensor_trip_point_api != NULL)
127                 sensor_mod_ctx.sensor_trip_point_api->notify_sensor_trip_point(
128                     id, ctx->trip_point_ctx->above_threshold, i);
129         }
130     }
131 }
132 #endif
133 
134 /*
135  * Module API
136  */
get_data(fwk_id_t id,struct mod_sensor_data * data)137 static int get_data(fwk_id_t id, struct mod_sensor_data *data)
138 {
139     int status;
140     struct sensor_dev_ctx *ctx;
141     struct fwk_event req;
142     struct mod_sensor_event_params *event_params =
143         (struct mod_sensor_event_params *)req.params;
144 
145     status = get_ctx_if_valid_call(id, data, &ctx);
146     if (status != FWK_SUCCESS) {
147         return status;
148     }
149 
150     if (ctx->concurrency_readings.dequeuing) {
151         /* Prevent new reading request while dequeuing pending readings
152          * cached data is returned
153          */
154         sensor_data_copy(data, &ctx->last_read);
155         return ctx->last_read.status;
156     }
157 
158     if (ctx->concurrency_readings.pending_requests == 0) {
159         status = ctx->driver_api->get_value(
160             ctx->config->driver_id, &ctx->last_read.value);
161         ctx->last_read.status = status;
162         if (status == FWK_SUCCESS) {
163 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
164             trip_point_process(id, &ctx->last_read);
165 #endif
166 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
167             ctx->last_read.timestamp = sensor_get_timestamp(id);
168 #endif
169             sensor_data_copy(data, &ctx->last_read);
170 
171             return status;
172         } else if (status != FWK_PENDING) {
173             return status;
174         }
175     }
176 
177     if (ctx->concurrency_readings.pending_requests >=
178         SENSOR_MAX_PENDING_REQUESTS) {
179         return FWK_E_BUSY;
180     }
181 
182     req = (struct fwk_event){
183         .target_id = id,
184         .id = mod_sensor_event_id_read_request,
185         .response_requested = true,
186     };
187 
188     /* Save data address to copy return values in there */
189     event_params->sensor_data = data;
190 
191     status = fwk_put_event(&req);
192     if (status != FWK_SUCCESS) {
193         return status;
194     }
195 
196     ctx->concurrency_readings.pending_requests++;
197     /*
198      * We return FWK_PENDING here to indicate to the caller that the
199      * result of the request is pending and will arrive later through
200      * an event.
201      */
202     return FWK_PENDING;
203 }
204 
get_info(fwk_id_t id,struct mod_sensor_complete_info * info)205 static int get_info(fwk_id_t id, struct mod_sensor_complete_info *info)
206 {
207     int status;
208     struct sensor_dev_ctx *ctx;
209 
210     status = get_ctx_if_valid_call(id, info, &ctx);
211     if (status != FWK_SUCCESS) {
212         return status;
213     }
214 
215     status = ctx->driver_api->get_info(ctx->config->driver_id, &info->hal_info);
216     if (!fwk_expect(status == FWK_SUCCESS)) {
217         return FWK_E_DEVICE;
218     }
219     info->trip_point = ctx->config->trip_point;
220 
221 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
222     status = sensor_get_timestamp_config(id, &info->timestamp);
223     if (status == FWK_E_SUPPORT) {
224         info->timestamp.timestamp_support = false;
225     } else {
226         return status;
227     }
228 #endif
229 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
230     if (ctx->axis_count > 1) {
231         info->multi_axis.support = true;
232         info->multi_axis.axis_count = ctx->axis_count;
233     }
234 #endif
235 
236     return FWK_SUCCESS;
237 }
238 
sensor_get_trip_point(fwk_id_t id,uint32_t trip_point_idx,struct mod_sensor_trip_point_params * params)239 static int sensor_get_trip_point(
240     fwk_id_t id,
241     uint32_t trip_point_idx,
242     struct mod_sensor_trip_point_params *params)
243 {
244     struct sensor_dev_ctx *ctx;
245 
246     fwk_check(params != NULL);
247 
248     ctx = ctx_table + fwk_id_get_element_idx(id);
249 
250     if (trip_point_idx >= ctx->config->trip_point.count) {
251         return FWK_E_PARAM;
252     }
253 
254     *params = ctx->trip_point_ctx[trip_point_idx].params;
255 
256     return FWK_SUCCESS;
257 }
258 
sensor_set_trip_point(fwk_id_t id,uint32_t trip_point_idx,struct mod_sensor_trip_point_params * params)259 static int sensor_set_trip_point(
260     fwk_id_t id,
261     uint32_t trip_point_idx,
262     struct mod_sensor_trip_point_params *params)
263 {
264     struct sensor_dev_ctx *ctx;
265 
266     if (params == NULL) {
267         return FWK_E_PARAM;
268     }
269 
270     ctx = ctx_table + fwk_id_get_element_idx(id);
271 
272     if (trip_point_idx >= ctx->config->trip_point.count) {
273         return FWK_E_PARAM;
274     }
275 
276     ctx->trip_point_ctx[trip_point_idx].params = *params;
277 
278     /* Clear the trip point flag */
279     ctx->trip_point_ctx[trip_point_idx].above_threshold = false;
280     return FWK_SUCCESS;
281 }
282 
283 static struct mod_sensor_api sensor_api = {
284     .get_data = get_data,
285     .get_info = get_info,
286     .get_trip_point = sensor_get_trip_point,
287     .set_trip_point = sensor_set_trip_point,
288 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
289     .set_timestamp_config = sensor_set_timestamp_config,
290     .get_timestamp_config = sensor_get_timestamp_config,
291 #endif
292 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
293     .get_axis_info = sensor_get_axis_info,
294 #endif
295 };
296 
297 /*
298  * Driver response API.
299  */
reading_complete(fwk_id_t dev_id,struct mod_sensor_driver_resp_params * response)300 static void reading_complete(fwk_id_t dev_id,
301                              struct mod_sensor_driver_resp_params *response)
302 {
303     int status = FWK_SUCCESS;
304     struct fwk_event event;
305     struct sensor_dev_ctx *ctx;
306 
307     if (!fwk_expect(fwk_id_get_module_idx(dev_id) == FWK_MODULE_IDX_SENSOR)) {
308         return;
309     }
310 
311     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
312     event = (struct fwk_event) {
313         .id = mod_sensor_event_id_read_complete,
314         .source_id = ctx->config->driver_id,
315         .target_id = dev_id,
316     };
317 
318     if (response != NULL) {
319         ctx->last_read.status = response->status;
320 
321 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
322         ctx->last_read.timestamp = sensor_get_timestamp(dev_id);
323 #endif
324 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
325         if (ctx->axis_count > 1) {
326             fwk_str_memcpy(
327                 ctx->last_read.axis_value,
328                 response->axis_value,
329                 sizeof(uint64_t) * ctx->axis_count);
330         } else {
331             ctx->last_read.value = response->value;
332         }
333 #else
334         ctx->last_read.value = response->value;
335 #endif
336 
337 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
338         trip_point_process(dev_id, &ctx->last_read);
339 #endif
340     } else {
341         ctx->last_read.status = FWK_E_DEVICE;
342     }
343 
344     ctx->concurrency_readings.dequeuing = true;
345 
346     status = fwk_put_event(&event);
347     fwk_assert(status == FWK_SUCCESS);
348 }
349 
350 static struct mod_sensor_driver_response_api sensor_driver_response_api = {
351     .reading_complete = reading_complete,
352 };
353 
354 /*
355  * Framework handlers
356  */
sensor_init(fwk_id_t module_id,unsigned int element_count,const void * data)357 static int sensor_init(
358     fwk_id_t module_id,
359     unsigned int element_count,
360     const void *data)
361 {
362     struct mod_sensor_config *config;
363 
364     ctx_table = fwk_mm_calloc(element_count, sizeof(ctx_table[0]));
365     fwk_str_memset(&sensor_mod_ctx, 0, sizeof(sensor_mod_ctx));
366     config = (struct mod_sensor_config *)data;
367 
368     sensor_mod_ctx.config = config;
369     return FWK_SUCCESS;
370 }
371 
sensor_dev_init(fwk_id_t element_id,unsigned int unused,const void * data)372 static int sensor_dev_init(fwk_id_t element_id,
373                            unsigned int unused,
374                            const void *data)
375 {
376     struct sensor_dev_ctx *ctx;
377     struct mod_sensor_dev_config *config;
378 
379     ctx = ctx_table + fwk_id_get_element_idx(element_id);
380 
381     fwk_check(data != NULL);
382     config = (struct mod_sensor_dev_config*)data;
383 
384     ctx->config = config;
385 
386     if (config->trip_point.count > 0) {
387         ctx->trip_point_ctx = fwk_mm_calloc(
388             config->trip_point.count, sizeof(struct sensor_trip_point_ctx));
389         ctx->trip_point_ctx->enabled = true;
390     } else {
391         ctx->trip_point_ctx = NULL;
392     }
393 
394     /* Pre-init last read with an invalid status */
395     ctx->last_read.status = FWK_E_DEVICE;
396 
397 #ifndef BUILD_HAS_SENSOR_MULTI_AXIS
398     ctx->axis_count = 1;
399 #endif
400 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
401     return sensor_timestamp_dev_init(element_id, ctx);
402 #else
403     return FWK_SUCCESS;
404 #endif
405 }
406 
sensor_bind(fwk_id_t id,unsigned int round)407 static int sensor_bind(fwk_id_t id, unsigned int round)
408 {
409     struct sensor_dev_ctx *ctx;
410     int status;
411     struct mod_sensor_driver_api *driver = NULL;
412 
413     if (round > 0) {
414         /*
415          * Only bind in first round of calls
416          */
417         return FWK_SUCCESS;
418     }
419     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
420         if (sensor_mod_ctx.config == NULL) {
421             return FWK_SUCCESS;
422         }
423 
424 #ifdef BUILD_HAS_NOTIFICATION
425         if (fwk_id_is_equal(
426                 sensor_mod_ctx.config->notification_id, FWK_ID_NONE)) {
427             return FWK_SUCCESS;
428         }
429 
430         return fwk_module_bind(
431             sensor_mod_ctx.config->notification_id,
432             sensor_mod_ctx.config->trip_point_api_id,
433             &sensor_mod_ctx.sensor_trip_point_api);
434 #else
435         return FWK_SUCCESS;
436 #endif
437     }
438     ctx = ctx_table + fwk_id_get_element_idx(id);
439     /* Bind to driver */
440     status = fwk_module_bind(ctx->config->driver_id,
441         ctx->config->driver_api_id,
442         &driver);
443     if (status != FWK_SUCCESS) {
444         return status;
445     }
446 
447     /* Validate driver API */
448     if ((driver == NULL) || (driver->get_value == NULL)) {
449         return FWK_E_DATA;
450     }
451 
452     ctx->driver_api = driver;
453 
454     return FWK_SUCCESS;
455 }
456 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
sensor_start(fwk_id_t id)457 int sensor_start(fwk_id_t id)
458 {
459     int status;
460 
461     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
462         return FWK_SUCCESS;
463     }
464     status = sensor_axis_start(id);
465     if (status != FWK_SUCCESS) {
466         return status;
467     }
468     return FWK_SUCCESS;
469 }
470 #endif
471 
sensor_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)472 static int sensor_process_bind_request(fwk_id_t source_id,
473                                        fwk_id_t target_id,
474                                        fwk_id_t api_id,
475                                        const void **api)
476 {
477     struct sensor_dev_ctx *ctx;
478     fwk_id_t driver_id;
479 
480     if (fwk_id_is_equal(api_id, mod_sensor_api_id_sensor)) {
481         *api = &sensor_api;
482 
483         return FWK_SUCCESS;
484     }
485 
486     if (fwk_id_is_equal(api_id, mod_sensor_api_id_driver_response)) {
487         if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
488             return FWK_E_PARAM;
489         }
490 
491         ctx = ctx_table + fwk_id_get_element_idx(target_id);
492         driver_id = ctx->config->driver_id;
493 
494         /* Allow element to sub-element binding */
495         if ((fwk_id_get_module_idx(driver_id) ==
496             fwk_id_get_module_idx(source_id)) &&
497             (fwk_id_get_element_idx(driver_id) ==
498             fwk_id_get_element_idx(source_id))) {
499 
500             *api = &sensor_driver_response_api;
501 
502             return FWK_SUCCESS;
503         } else {
504             return FWK_E_ACCESS;
505         }
506     }
507 
508     return FWK_E_PARAM;
509 }
510 
process_pending_requests(fwk_id_t dev_id,const struct mod_sensor_data * event_params)511 static int process_pending_requests(
512     fwk_id_t dev_id,
513     const struct mod_sensor_data *event_params)
514 {
515     int status;
516     bool list_is_empty;
517     struct fwk_event delayed_response;
518     struct mod_sensor_event_params *response_params =
519         (struct mod_sensor_event_params *)delayed_response.params;
520     struct sensor_dev_ctx *ctx;
521 
522     status = fwk_is_delayed_response_list_empty(dev_id, &list_is_empty);
523     if (status != FWK_SUCCESS) {
524         return status;
525     }
526 
527     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
528 
529     for (; !list_is_empty && ctx->concurrency_readings.pending_requests > 0;
530          ctx->concurrency_readings.pending_requests--) {
531         status = fwk_get_first_delayed_response(dev_id, &delayed_response);
532         if (status != FWK_SUCCESS) {
533             return status;
534         }
535 
536         sensor_data_copy(response_params->sensor_data, &ctx->last_read);
537 
538         status = fwk_put_event(&delayed_response);
539         if (status != FWK_SUCCESS) {
540             return status;
541         }
542 
543         status = fwk_is_delayed_response_list_empty(dev_id, &list_is_empty);
544         if (status != FWK_SUCCESS) {
545             return status;
546         }
547     }
548 
549     ctx->concurrency_readings.pending_requests = 0;
550     ctx->concurrency_readings.dequeuing = false;
551 
552     return FWK_SUCCESS;
553 }
554 
sensor_process_event(const struct fwk_event * event,struct fwk_event * resp_event)555 static int sensor_process_event(const struct fwk_event *event,
556                                 struct fwk_event *resp_event)
557 {
558     int status;
559     struct sensor_dev_ctx *ctx;
560     struct fwk_event read_req_event;
561     struct mod_sensor_event_params *event_params =
562         (struct mod_sensor_event_params *)read_req_event.params;
563     enum mod_sensor_event_idx event_id_type;
564 
565     if (!fwk_module_is_valid_element_id(event->target_id)) {
566         return FWK_E_PARAM;
567     }
568 
569     ctx = ctx_table + fwk_id_get_element_idx(event->target_id);
570 
571     event_id_type = (enum mod_sensor_event_idx)fwk_id_get_event_idx(event->id);
572 
573     switch (event_id_type) {
574     case SENSOR_EVENT_IDX_READ_REQUEST:
575         if (ctx->concurrency_readings.pending_requests == 1) {
576             /*
577              * We keep the cookie event of the request that triggers the
578              * reading.
579              */
580             ctx->cookie = event->cookie;
581         }
582         resp_event->is_delayed_response = true;
583 
584         return FWK_SUCCESS;
585 
586     case SENSOR_EVENT_IDX_READ_COMPLETE:
587         status = fwk_get_delayed_response(
588             event->target_id, ctx->cookie, &read_req_event);
589         if (status != FWK_SUCCESS) {
590             return status;
591         }
592 
593         sensor_data_copy(
594             (struct mod_sensor_data *)event_params->sensor_data,
595             &ctx->last_read);
596 
597         status = fwk_put_event(&read_req_event);
598         if (status != FWK_SUCCESS) {
599             return status;
600         }
601 
602         /*
603          * After a read complete event all pending requests are processed.
604          * We are processing pending events until it reaches a new reading
605          * or the event queue is empty.
606          */
607         return process_pending_requests(
608             event->target_id, (const struct mod_sensor_data *)event->params);
609 
610     default:
611         return FWK_E_PARAM;
612     }
613 }
614 
615 const struct fwk_module module_sensor = {
616     .api_count = (unsigned int)MOD_SENSOR_API_IDX_COUNT,
617     .event_count = (unsigned int)SENSOR_EVENT_IDX_COUNT,
618     .type = FWK_MODULE_TYPE_HAL,
619     .init = sensor_init,
620     .element_init = sensor_dev_init,
621     .bind = sensor_bind,
622 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
623     .start = sensor_start,
624 #endif
625     .process_bind_request = sensor_process_bind_request,
626     .process_event = sensor_process_event,
627 };
628