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