1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * Juno PVT Sensors driver.
9 */
10
11 #include "config_power_domain.h"
12 #include "juno_id.h"
13 #include "juno_pvt.h"
14 #include "pvt_sensor_calibration.h"
15 #include "system_clock.h"
16
17 #include <mod_juno_pvt.h>
18 #include <mod_power_domain.h>
19 #include <mod_sensor.h>
20
21 #include <fwk_assert.h>
22 #include <fwk_core.h>
23 #include <fwk_event.h>
24 #include <fwk_id.h>
25 #include <fwk_interrupt.h>
26 #include <fwk_mm.h>
27 #include <fwk_module.h>
28 #include <fwk_module_idx.h>
29 #include <fwk_notification.h>
30 #include <fwk_status.h>
31
32 #include <stdbool.h>
33 #include <stddef.h>
34
35 /* Location Identifier */
36 #define PVTGROUP_GROUP_INFO_LOC UINT32_C(0x00000001)
37
38 /* Group Based Register Identifier */
39 #define PVTGROUP_GROUP_INFO_LOC_GROUP_LITE UINT32_C(0x00000001)
40
41 /* Number of sensors in Group Field Mask */
42 #define PVTGROUP_SENSOR_COUNT_MASK UINT32_C(0x0000003E)
43
44 /* Group Measurement Enable */
45 #define PVTGROUP_MEASUREMENT_ENABLE UINT32_C(0x00000001)
46
47 /* Sensor Measurement mask for a sensor */
48 #define SAMPLE_VALUE_MASK UINT32_C(0x0000FFFF)
49
50 /* Sample Window time for a sensor */
51 #define SAMPLE_WINDOW_MASK UINT32_C(0x0000FFFF)
52
53 /* Interrupt masks */
54 #define IRQ_MASK_DATA_VALID UINT32_C(0x00000004)
55 #define IRQ_MASK_ALL UINT32_C(0x0000000F)
56 #define IRQ_MASK_ENABLED IRQ_MASK_DATA_VALID
57 #define IRQ_MASK_DISABLED ~IRQ_MASK_ENABLED
58
59 /* Sampling Options */
60 #define FULL_SCALE_TEMP 200 /* Degrees Celsius */
61 #define FULL_SCALE_MVOLT 1000 /* Milli Volts */
62
63 /* Constant temperature offset for Juno R1 & R2 [millidegrees] */
64 #define R1_TEMP_OFFSET 9000
65
66 #define REFCLK_KHZ (CLOCK_RATE_REFCLK / 1000)
67
68 /* Module context */
69 struct pvt_ctx {
70 /* Board revision */
71 enum juno_idx_revision board_rev;
72
73 /* Flag indicating whether the driver is disabled */
74 bool driver_is_disabled;
75
76 /* Elements count */
77 unsigned int elem_count;
78 };
79
80 /*
81 * Sensors are grouped in elements and each sensor is represented by a
82 * sub-element.
83 */
84
85 /* Group (element) context */
86 struct pvt_dev_ctx {
87 /*
88 * Pointer to table of individual sensors (sub-elements) configuration data
89 */
90 struct mod_juno_pvt_dev_config *sensor_cfg_table;
91
92 /* Pointer to the table of sensor context */
93 struct pvt_sub_dev_ctx *sensor_ctx_table;
94
95 /* Identifier of the sensor (sub-element) being processed */
96 fwk_id_t sensor_read_id;
97
98 /* Sensor Driver Input API */
99 const struct mod_sensor_driver_response_api *driver_response_api;
100
101 /* Tracker to Power Domain ON state */
102 bool pd_state_on;
103
104 /* Cookie of the notification to respond to */
105 uint32_t cookie;
106
107 /*
108 * Power Domain notification delayed flag
109 *
110 * If a pre-state notification is received when the sensor reading is in
111 * progress, the response to the notification is delayed until the sensor
112 * reading is completed.
113 */
114 bool pd_notification_delayed;
115 };
116
117 /* Sensor (sub-element) context */
118 struct pvt_sub_dev_ctx {
119 /* Last raw reading from the sensor */
120 uint32_t last_reading;
121
122 /* Sample Window for measurement */
123 unsigned int sample_window;
124
125 /* Slope coefficient for measurement */
126 int slope_m;
127
128 /* Offset coefficient for measurement */
129 int freq_b;
130
131 /* Sensor HAL Identifier */
132 fwk_id_t sensor_hal_id;
133 };
134
135 /* Events indices */
136 enum pvt_event_idx {
137 JUNO_PVT_EVENT_IDX_READ_REQUEST,
138 JUNO_PVT_EVENT_IDX_DATA_READY,
139 JUNO_PVT_EVENT_IDX_COUNT
140 };
141
142 static struct pvt_ctx mod_ctx;
143 static struct pvt_dev_ctx *dev_ctx;
144
145 static fwk_id_t dbgsys_pd_id =
146 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_POWER_DOMAIN, POWER_DOMAIN_IDX_DBGSYS);
147
148 /*
149 * Static helper functions
150 */
151
152 /*
153 * For the temperature-based sensors, there are two calibration points:
154 * 45 degrees C and 85 degrees C
155 *
156 * The maths in this function considers temperature on the X-axis and
157 * sensor readings on the Y-axis.
158 */
process_pvt_calibration(struct pvt_sub_dev_ctx * sensor_ctx,uint16_t cal_45C,uint16_t cal_85C)159 static int process_pvt_calibration(struct pvt_sub_dev_ctx *sensor_ctx,
160 uint16_t cal_45C,
161 uint16_t cal_85C)
162 {
163 unsigned int freq_45;
164 unsigned int freq_85;
165 unsigned int freq_fs;
166 unsigned int sample_window;
167 int freq_b;
168 int slope_m;
169
170 if ((cal_45C == 0) || (cal_85C == 0)) {
171 return FWK_E_PARAM;
172 }
173
174 /* Convert into kHz */
175 freq_45 = (unsigned int)(cal_45C * 10);
176 freq_85 = (unsigned int)(cal_85C * 10);
177
178 /* Find the slope */
179 slope_m = (int)((freq_85 - freq_45) / (85 - 45));
180 if (!fwk_expect(slope_m != 0)) {
181 return FWK_E_PARAM;
182 }
183
184 /* Find the intercept of the line */
185 freq_b = (int)(freq_85 - (slope_m * 85));
186
187 /* Use line equation to find full-scale frequency */
188 freq_fs = (unsigned int)((slope_m * FULL_SCALE_TEMP) + freq_b);
189
190 /*
191 * freq_fs must always be bigger than or equal to REFCLK_KHZ or
192 * sample_window calculation won't work.
193 */
194 if (freq_fs < REFCLK_KHZ) {
195 return FWK_E_RANGE;
196 }
197
198 /* Calculate sample window to fit the full scale reading */
199 sample_window = (SAMPLE_WINDOW_MASK * REFCLK_KHZ) / freq_fs;
200 if (sample_window > SAMPLE_WINDOW_MASK) {
201 return FWK_E_PARAM;
202 }
203
204 /* Store constants for run-time calculations */
205 sensor_ctx->slope_m = slope_m;
206 sensor_ctx->freq_b = freq_b;
207 sensor_ctx->sample_window = sample_window;
208
209 return FWK_SUCCESS;
210 }
211
212 /*
213 * For the ring oscillator based sensors, there are two calibration points:
214 * 810mV and 900mV
215 *
216 * The maths in this function considers mV on the X-axis and sensor readings
217 * on the Y-axis.
218 */
process_osc_calibration(struct pvt_sub_dev_ctx * sensor_ctx,uint16_t cal_810,uint16_t cal_900)219 static int process_osc_calibration(struct pvt_sub_dev_ctx *sensor_ctx,
220 uint16_t cal_810,
221 uint16_t cal_900)
222 {
223 unsigned int freq_810;
224 unsigned int freq_900;
225 unsigned int freq_fs;
226 unsigned int freq_b;
227 unsigned int sample_window;
228 unsigned int slope_m;
229
230 if ((cal_810 == 0) || (cal_900 == 0)) {
231 return FWK_E_PARAM;
232 }
233
234 /* Convert into kHz */
235 freq_810 = (unsigned int)(cal_810 * 20);
236 freq_900 = (unsigned int)(cal_900 * 20);
237
238 /* Find the slope */
239 slope_m = (freq_900 - freq_810) / (900 - 810);
240
241 /* Find the intercept of the line */
242 freq_b = freq_900 - (slope_m * 900);
243
244 /* Use line equation to find full-scale frequency */
245 freq_fs = (slope_m * FULL_SCALE_MVOLT) + freq_b;
246
247 /*
248 * freq_fs must be always bigger than or equal to REFCLK_KHZ or
249 * sample_window calculation won't work.
250 */
251 if (freq_fs < REFCLK_KHZ) {
252 return FWK_E_RANGE;
253 }
254
255 /* Calculate sample window to fit the full scale reading */
256 sample_window = (SAMPLE_WINDOW_MASK * REFCLK_KHZ) / freq_fs;
257 if (sample_window > SAMPLE_WINDOW_MASK) {
258 return FWK_E_PARAM;
259 }
260
261 /* Store constants for the run-time calculations */
262 sensor_ctx->slope_m = (int)slope_m;
263 sensor_ctx->freq_b = (int)freq_b;
264 sensor_ctx->sample_window = sample_window;
265
266 return FWK_SUCCESS;
267 }
268
pvt_interrupt_handler(uintptr_t param)269 static void pvt_interrupt_handler(uintptr_t param)
270 {
271 struct mod_juno_pvt_dev_config *sensor_cfg;
272 uint32_t osc_counter = 0, sensor_value;
273 int freq_khz;
274 uint64_t value = 0;
275 int status = FWK_E_PARAM;
276 struct fwk_event event;
277 struct pvt_dev_ctx *group_ctx;
278 struct pvt_sub_dev_ctx *sensor_ctx;
279 struct mod_sensor_driver_resp_params *isr_params =
280 (struct mod_sensor_driver_resp_params *)event.params;
281 uint8_t sub_elt_idx;
282
283 group_ctx = (struct pvt_dev_ctx *)param;
284 sub_elt_idx =
285 (uint8_t)fwk_id_get_sub_element_idx(group_ctx->sensor_read_id);
286 sensor_cfg = &group_ctx->sensor_cfg_table[sub_elt_idx];
287 sensor_ctx = &group_ctx->sensor_ctx_table[sub_elt_idx];
288
289 sensor_cfg->group->regs->IRQ_CLEAR = IRQ_MASK_ALL;
290
291 if (((sensor_cfg->group->regs->SENSOR_DATA_VALID &
292 (uint32_t)(1U << sensor_cfg->index))) != (uint32_t)0) {
293 osc_counter = sensor_cfg->group->regs->SENSOR_DATA[sensor_cfg->index] &
294 SAMPLE_VALUE_MASK;
295 } else {
296 /* Return the last raw reading */
297 value = (uint64_t)sensor_ctx->last_reading;
298 status = FWK_SUCCESS;
299
300 goto exit;
301 }
302
303 sensor_ctx->last_reading = osc_counter;
304
305 if (!fwk_expect(sensor_ctx->sample_window != 0)) {
306 goto exit;
307 }
308
309 freq_khz = (int)((osc_counter * REFCLK_KHZ) / sensor_ctx->sample_window);
310
311 fwk_assert(sensor_ctx->slope_m != 0);
312
313 sensor_value = (uint32_t)(
314 ((freq_khz - sensor_ctx->freq_b) * 1000) / sensor_ctx->slope_m);
315
316 if (sensor_cfg->type == JUNO_PVT_TYPE_TEMP) {
317 if ((mod_ctx.board_rev == JUNO_IDX_REVISION_R1) ||
318 (mod_ctx.board_rev == JUNO_IDX_REVISION_R2)) {
319 sensor_value -= R1_TEMP_OFFSET;
320 }
321
322 value = (uint64_t)sensor_value;
323 status = FWK_SUCCESS;
324 } else if (sensor_cfg->type == JUNO_PVT_TYPE_VOLT) {
325 /* Convert to millivolts */
326 sensor_value /= 1000;
327
328 value = (uint64_t)sensor_value;
329 status = FWK_SUCCESS;
330 } else {
331 status = FWK_E_PARAM;
332 }
333
334 exit:
335 event = (struct fwk_event) {
336 .target_id = fwk_id_build_element_id(
337 fwk_module_id_juno_pvt,
338 fwk_id_get_element_idx(group_ctx->sensor_read_id)),
339 .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_JUNO_PVT),
340 .id = FWK_ID_EVENT(FWK_MODULE_IDX_JUNO_PVT,
341 JUNO_PVT_EVENT_IDX_DATA_READY),
342 };
343
344 isr_params->status = status;
345 isr_params->value = value;
346
347 status = fwk_put_event(&event);
348 fwk_assert(status == FWK_SUCCESS);
349 }
350
respond(struct pvt_dev_ctx * group_ctx)351 static int respond(struct pvt_dev_ctx *group_ctx)
352 {
353 struct pvt_sub_dev_ctx *sensor_ctx;
354
355 /* The request to initiate the reading failed, respond back */
356 struct mod_sensor_driver_resp_params resp_params = {0};
357 resp_params.status = FWK_E_STATE;
358
359 sensor_ctx = &group_ctx->sensor_ctx_table[
360 fwk_id_get_sub_element_idx(group_ctx->sensor_read_id)];
361
362 group_ctx->driver_response_api->reading_complete(
363 sensor_ctx->sensor_hal_id,
364 &resp_params);
365
366 group_ctx->sensor_read_id = FWK_ID_NONE;
367
368 return FWK_E_STATE;
369 }
370
371 /*
372 * PVT driver API functions
373 */
get_info(fwk_id_t id,struct mod_sensor_info * info)374 static int get_info(fwk_id_t id, struct mod_sensor_info *info)
375 {
376 struct mod_juno_pvt_dev_config *sensor_cfg;
377 struct pvt_dev_ctx *group_ctx;
378
379 if (mod_ctx.driver_is_disabled) {
380 return FWK_E_DEVICE;
381 }
382
383 group_ctx = &dev_ctx[fwk_id_get_element_idx(id)];
384 sensor_cfg = &group_ctx->sensor_cfg_table[fwk_id_get_sub_element_idx(id)];
385
386 fwk_assert(sensor_cfg != NULL);
387
388 *info = *(sensor_cfg->info);
389
390 return FWK_SUCCESS;
391 }
392
get_value(fwk_id_t id,mod_sensor_value_t * value)393 static int get_value(fwk_id_t id, mod_sensor_value_t *value)
394 {
395 #ifdef BUILD_HAS_SENSOR_SIGNED_VALUE
396 return FWK_E_SUPPORT;
397 #else
398 uint8_t elt_idx;
399 struct pvt_dev_ctx *group_ctx;
400 struct fwk_event read_req;
401 int status;
402
403 if (mod_ctx.driver_is_disabled) {
404 return FWK_E_DEVICE;
405 }
406
407 elt_idx = (uint8_t)fwk_id_get_element_idx(id);
408 group_ctx = &dev_ctx[elt_idx];
409
410 if (!group_ctx->pd_state_on) {
411 return FWK_E_PWRSTATE;
412 }
413
414 if (fwk_id_is_equal(group_ctx->sensor_read_id, FWK_ID_NONE)) {
415 /* No other sensors within the group are being read, mark this one */
416 group_ctx->sensor_read_id = id;
417
418 read_req = (struct fwk_event) {
419 .target_id = fwk_id_build_element_id(fwk_module_id_juno_pvt,
420 elt_idx),
421 .id = FWK_ID_EVENT(FWK_MODULE_IDX_JUNO_PVT,
422 JUNO_PVT_EVENT_IDX_READ_REQUEST),
423 };
424
425 status = fwk_put_event(&read_req);
426 } else {
427 /* At least one sensor is being read, the sensor group is busy */
428 status = FWK_E_BUSY;
429 }
430
431 if (status == FWK_SUCCESS) {
432 return FWK_PENDING;
433 }
434
435 return status;
436 #endif
437 }
438
439 static const struct mod_sensor_driver_api pvt_sensor_api = {
440 .get_info = get_info,
441 .get_value = get_value,
442 };
443
444 /*
445 * Framework handler functions
446 */
447
juno_pvt_init(fwk_id_t module_id,unsigned int element_count,const void * data)448 static int juno_pvt_init(fwk_id_t module_id,
449 unsigned int element_count,
450 const void *data)
451 {
452 int status;
453 enum juno_idx_platform plat;
454
455 if (element_count == 0) {
456 return FWK_E_PARAM;
457 }
458
459 dev_ctx = fwk_mm_calloc(element_count, sizeof(struct pvt_dev_ctx));
460
461 status = juno_id_get_platform(&plat);
462 if (status != FWK_SUCCESS) {
463 return status;
464 }
465
466 if (plat == JUNO_IDX_PLATFORM_FVP) {
467 mod_ctx.driver_is_disabled = true;
468 }
469
470 status = juno_id_get_revision(&mod_ctx.board_rev);
471 if (status != FWK_SUCCESS) {
472 return status;
473 }
474
475 mod_ctx.elem_count = element_count;
476
477 return FWK_SUCCESS;
478 }
479
juno_pvt_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)480 static int juno_pvt_element_init(fwk_id_t element_id,
481 unsigned int sub_element_count,
482 const void *data)
483 {
484 struct pvt_dev_ctx *group_ctx;
485
486 if (mod_ctx.driver_is_disabled) {
487 return FWK_SUCCESS;
488 }
489
490 /* When no sub-elements are defined, the group is not defined */
491 if (sub_element_count == 0) {
492 return FWK_SUCCESS;
493 }
494
495 group_ctx = &dev_ctx[fwk_id_get_element_idx(element_id)];
496
497 group_ctx->sensor_ctx_table =
498 fwk_mm_calloc(sub_element_count, sizeof(struct pvt_sub_dev_ctx));
499
500 group_ctx->sensor_cfg_table = (struct mod_juno_pvt_dev_config *)data;
501 group_ctx->sensor_read_id = FWK_ID_NONE;
502
503 return FWK_SUCCESS;
504 }
505
juno_pvt_bind(fwk_id_t id,unsigned int round)506 static int juno_pvt_bind(fwk_id_t id, unsigned int round)
507 {
508 int status;
509 int sub_element_count;
510 struct pvt_dev_ctx *group_ctx;
511 struct pvt_sub_dev_ctx *sensor_ctx;
512
513 /* Bind in the second round */
514 if ((round == 0) || mod_ctx.driver_is_disabled ||
515 fwk_module_is_valid_module_id(id)) {
516 return FWK_SUCCESS;
517 }
518
519 group_ctx = &dev_ctx[fwk_id_get_element_idx(id)];
520
521 sub_element_count = fwk_module_get_sub_element_count(id);
522 if (sub_element_count < 0) {
523 return FWK_E_DATA;
524 }
525
526 /*
527 * When no sub-elements are defined, there sensor group does not require
528 * binding.
529 */
530 if (sub_element_count == 0) {
531 return FWK_SUCCESS;
532 }
533
534 /*
535 * Bind to sensor HAL module
536 *
537 * The first sensor sub_element identifier for each group is used to bind to
538 * sensor module. The sensor HAL module has already bound to us at this
539 * point, so we know that sensor_hal_id is initialized correctly.
540 */
541 sensor_ctx = &group_ctx->sensor_ctx_table[0];
542
543 status = fwk_module_bind(sensor_ctx->sensor_hal_id,
544 mod_sensor_api_id_driver_response,
545 &group_ctx->driver_response_api);
546 if (status != FWK_SUCCESS) {
547 return status;
548 }
549
550 return FWK_SUCCESS;
551 }
552
juno_pvt_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_type,const void ** api)553 static int juno_pvt_process_bind_request(fwk_id_t source_id,
554 fwk_id_t target_id,
555 fwk_id_t api_type,
556 const void **api)
557 {
558 struct pvt_dev_ctx *group_ctx;
559 struct pvt_sub_dev_ctx *sensor_ctx;
560
561 if ((!fwk_module_is_valid_element_id(source_id)) ||
562 (!fwk_module_is_valid_sub_element_id(target_id)) ||
563 (fwk_id_get_module_idx(source_id) != FWK_MODULE_IDX_SENSOR) ||
564 (mod_ctx.driver_is_disabled)) {
565 return FWK_E_ACCESS;
566 }
567
568 group_ctx = &dev_ctx[fwk_id_get_element_idx(target_id)];
569 sensor_ctx = &group_ctx->sensor_ctx_table[
570 fwk_id_get_sub_element_idx(target_id)];
571
572 sensor_ctx->sensor_hal_id = source_id;
573
574 *api = &pvt_sensor_api;
575
576 return FWK_SUCCESS;
577 }
578
pvt_start(fwk_id_t id)579 static int pvt_start(fwk_id_t id)
580 {
581 int status;
582 struct mod_juno_pvt_dev_config *sensor_cfg;
583 int sub_element_count;
584 struct pvt_dev_ctx *group_ctx;
585 struct pvt_sub_dev_ctx *sensor_ctx;
586 uint16_t calibration_a;
587 uint16_t calibration_b;
588 uint8_t sub_elem_ix;
589
590 if (mod_ctx.driver_is_disabled) {
591 return FWK_SUCCESS;
592 }
593
594 if (fwk_module_is_valid_module_id(id)) {
595
596 /* Verify the board has the calibration data */
597 if ((JUNO_PVT_CALIBRATION->PART_ID_PREFIX != 'C') &&
598 (JUNO_PVT_CALIBRATION->PART_ID_PREFIX != 'D') &&
599 (JUNO_PVT_CALIBRATION->PART_ID_PREFIX != 'E') &&
600 (JUNO_PVT_CALIBRATION->PART_ID_PREFIX != 'F') &&
601 (JUNO_PVT_CALIBRATION->PART_ID_PREFIX != 'G')) {
602 mod_ctx.driver_is_disabled = true;
603
604 return FWK_E_PARAM;
605 }
606
607 status = fwk_notification_subscribe(
608 mod_pd_notification_id_power_state_transition, dbgsys_pd_id, id);
609 if (status != FWK_SUCCESS) {
610 return status;
611 }
612
613 return FWK_SUCCESS;
614 }
615
616 group_ctx = &dev_ctx[fwk_id_get_element_idx(id)];
617
618 sub_element_count = fwk_module_get_sub_element_count(id);
619 if (sub_element_count < 0) {
620 return FWK_E_DATA;
621 }
622
623 /*
624 * When no sub-elements are defined, there are no sensors to be
625 * calibrated.
626 */
627 if (sub_element_count == 0) {
628 return FWK_SUCCESS;
629 }
630
631 /* Perform calibration for each sensor within the group */
632 for (sub_elem_ix = 0; sub_elem_ix < (uint8_t)sub_element_count;
633 sub_elem_ix++) {
634 sensor_ctx = &group_ctx->sensor_ctx_table[sub_elem_ix];
635 sensor_cfg = &group_ctx->sensor_cfg_table[sub_elem_ix];
636
637 fwk_check(sensor_cfg->cal_reg_a != NULL);
638 fwk_check(sensor_cfg->cal_reg_b != NULL);
639
640 calibration_a = *(sensor_cfg->cal_reg_a) + sensor_cfg->offset_cal_reg_a;
641 calibration_b = *(sensor_cfg->cal_reg_b) + sensor_cfg->offset_cal_reg_b;
642
643 switch (sensor_cfg->type) {
644 case JUNO_PVT_TYPE_TEMP:
645 status = process_pvt_calibration(sensor_ctx,
646 calibration_a,
647 calibration_b);
648 break;
649
650 case JUNO_PVT_TYPE_VOLT:
651 status = process_osc_calibration(sensor_ctx,
652 calibration_a,
653 calibration_b);
654 break;
655
656 default:
657 status = FWK_E_PARAM;
658
659 break;
660 }
661
662 if (status != FWK_SUCCESS) {
663 goto error;
664 }
665 }
666
667 sensor_cfg = group_ctx->sensor_cfg_table;
668
669 status = fwk_notification_subscribe(
670 mod_pd_notification_id_power_state_pre_transition,
671 sensor_cfg->group->pd_id,
672 id);
673 if (status != FWK_SUCCESS) {
674 return status;
675 }
676
677 status = fwk_notification_subscribe(
678 mod_pd_notification_id_power_state_transition,
679 sensor_cfg->group->pd_id,
680 id);
681 if (status != FWK_SUCCESS) {
682 return status;
683 }
684
685 return FWK_SUCCESS;
686
687 error:
688 mod_ctx.driver_is_disabled = true;
689
690 return status;
691 }
692
693 /*
694 * On Juno, the PPU denies to turn off clusters when DBGSYS is turned ON.
695 * In such case, disable all the notifications since no transitions for clusters
696 * will take place anymore.
697 */
unsubscribe_cluster_notif(void)698 static int unsubscribe_cluster_notif(void)
699 {
700 struct pvt_dev_ctx *group_ctx;
701 struct mod_juno_pvt_dev_config *sensor_cfg;
702 fwk_id_t id;
703 int status;
704
705 for (unsigned int i = 0; i < mod_ctx.elem_count; i++) {
706 if ((i != JUNO_PVT_GROUP_BIG) && (i != JUNO_PVT_GROUP_LITTLE)) {
707 continue;
708 }
709
710 group_ctx = &dev_ctx[i];
711
712 sensor_cfg = group_ctx->sensor_cfg_table;
713
714 id = FWK_ID_ELEMENT(FWK_MODULE_IDX_JUNO_PVT, i);
715
716 status = fwk_notification_unsubscribe(
717 mod_pd_notification_id_power_state_pre_transition,
718 sensor_cfg->group->pd_id,
719 id);
720 if (status != FWK_SUCCESS) {
721 return status;
722 }
723
724 status = fwk_notification_unsubscribe(
725 mod_pd_notification_id_power_state_transition,
726 sensor_cfg->group->pd_id,
727 id);
728 if (status != FWK_SUCCESS) {
729 return status;
730 }
731
732 group_ctx->pd_state_on = true;
733 }
734
735 return FWK_SUCCESS;
736 }
737
pvt_process_event(const struct fwk_event * event,struct fwk_event * resp_event)738 static int pvt_process_event(const struct fwk_event *event,
739 struct fwk_event *resp_event){
740 int status = FWK_SUCCESS;
741 struct mod_juno_pvt_dev_config *sensor_cfg;
742 const struct juno_group_desc *group;
743 struct pvt_dev_ctx *group_ctx;
744 struct pvt_sub_dev_ctx *sensor_ctx;
745 struct mod_sensor_driver_resp_params *isr_params =
746 (struct mod_sensor_driver_resp_params *)event->params;
747 struct fwk_event resp_notif;
748 uint8_t elt_idx = (uint8_t)fwk_id_get_element_idx(event->target_id);
749 unsigned int sub_elt_idx;
750 unsigned int sensor_count;
751 struct mod_pd_power_state_pre_transition_notification_resp_params
752 *pd_resp_params =
753 (struct mod_pd_power_state_pre_transition_notification_resp_params *)
754 resp_notif.params;
755
756 fwk_assert(fwk_module_is_valid_element_id(event->target_id));
757
758 group_ctx = &dev_ctx[elt_idx];
759 sub_elt_idx = fwk_id_get_sub_element_idx(group_ctx->sensor_read_id);
760 sensor_ctx = &group_ctx->sensor_ctx_table[sub_elt_idx];
761
762 switch ((enum pvt_event_idx)fwk_id_get_event_idx(event->id)) {
763 case JUNO_PVT_EVENT_IDX_READ_REQUEST:
764 sensor_cfg = &group_ctx->sensor_cfg_table[sub_elt_idx];
765
766 group = sensor_cfg->group;
767
768 if ((group->regs->GROUP_INFO & PVTGROUP_GROUP_INFO_LOC) !=
769 PVTGROUP_GROUP_INFO_LOC_GROUP_LITE) {
770 return respond(group_ctx);
771 }
772
773 sensor_count = (group->regs->GROUP_INFO &
774 PVTGROUP_SENSOR_COUNT_MASK) >> 1;
775
776 if (sensor_count < group->sensor_count) {
777 return respond(group_ctx);
778 }
779
780 /*
781 * Configure the group before reading a sensor within it.
782 * This must be performed each time because the configuration is lost
783 * if the power domain that the group resides in powers off.
784 */
785 group->regs->IRQ_MASK_CLEAR = IRQ_MASK_ENABLED;
786 group->regs->IRQ_MASK_SET = IRQ_MASK_DISABLED;
787 group->regs->IRQ_CLEAR = IRQ_MASK_ALL;
788 group->regs->SSI_RATE_DIV = 0;
789
790 status = fwk_interrupt_clear_pending(group->irq);
791 if (status != FWK_SUCCESS) {
792 return respond(group_ctx);
793 }
794
795 status = fwk_interrupt_set_isr_param(group->irq,
796 &pvt_interrupt_handler,
797 (uintptr_t)group_ctx);
798 if (status != FWK_SUCCESS) {
799 return respond(group_ctx);
800 }
801
802 status = fwk_interrupt_enable(group->irq);
803 if (status != FWK_SUCCESS) {
804 return respond(group_ctx);
805 }
806
807 /* Initiate measurement for group/sensor */
808 group->regs->SENSOR_ENABLE = (uint32_t)(1U << sensor_cfg->index);
809 group->regs->SAMPLE_WINDOW =
810 sensor_ctx->sample_window & SAMPLE_WINDOW_MASK;
811 group->regs->MEASUREMENT_ENABLE = PVTGROUP_MEASUREMENT_ENABLE;
812
813 return FWK_SUCCESS;
814
815 case JUNO_PVT_EVENT_IDX_DATA_READY:
816 if (fwk_id_get_element_idx(group_ctx->sensor_read_id) ==
817 fwk_id_get_element_idx(event->target_id)) {
818 /* Set the sensor group available */
819 group_ctx->sensor_read_id = FWK_ID_NONE;
820
821 group_ctx->driver_response_api->reading_complete(
822 sensor_ctx->sensor_hal_id,
823 isr_params);
824
825 /* Respond to the Power Domain notification */
826 if (group_ctx->pd_notification_delayed) {
827 group_ctx->pd_notification_delayed = false;
828 status = fwk_get_delayed_response(
829 event->target_id, group_ctx->cookie, &resp_notif);
830 if (status != FWK_SUCCESS) {
831 return FWK_E_PANIC;
832 }
833
834 pd_resp_params->status = FWK_SUCCESS;
835
836 status = fwk_put_event(&resp_notif);
837 if (status != FWK_SUCCESS) {
838 return FWK_E_PANIC;
839 }
840 }
841
842 return FWK_SUCCESS;
843 }
844 /* Fall-through */
845
846 default:
847 return FWK_E_PARAM;
848 }
849 }
850
pvt_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)851 static int pvt_process_notification(const struct fwk_event *event,
852 struct fwk_event *resp_event)
853 {
854 struct pvt_dev_ctx *group_ctx;
855 struct mod_pd_power_state_pre_transition_notification_params
856 *pre_state_params;
857 struct mod_pd_power_state_transition_notification_params
858 *post_state_params;
859 struct mod_pd_power_state_pre_transition_notification_resp_params
860 *resp_params;
861
862 if (fwk_id_is_equal(event->source_id, dbgsys_pd_id)) {
863 post_state_params =
864 (struct mod_pd_power_state_transition_notification_params *)
865 event->params;
866
867 if (post_state_params->state == MOD_PD_STATE_ON) {
868 return unsubscribe_cluster_notif();
869 }
870
871 return FWK_SUCCESS;
872 }
873
874 group_ctx = &dev_ctx[fwk_id_get_element_idx(event->target_id)];
875
876 if (fwk_id_is_equal(event->id,
877 mod_pd_notification_id_power_state_pre_transition)) {
878 pre_state_params =
879 (struct mod_pd_power_state_pre_transition_notification_params *)
880 event->params;
881 if (pre_state_params->target_state == MOD_PD_STATE_OFF) {
882 group_ctx->pd_state_on = false;
883 }
884
885 if (!fwk_id_is_equal(group_ctx->sensor_read_id, FWK_ID_NONE)) {
886 /* Read request ongoing, delay the response */
887 group_ctx->cookie = event->cookie;
888 group_ctx->pd_notification_delayed = true;
889
890 /*
891 * The response to Power Domain is delayed so we can process the
892 * sensor reading within a defined power state.
893 */
894 resp_event->is_delayed_response = true;
895 } else {
896 resp_params =
897 (struct
898 mod_pd_power_state_pre_transition_notification_resp_params *)
899 resp_event->params;
900
901 resp_params->status = FWK_SUCCESS;
902 }
903
904 } else if (fwk_id_is_equal(event->id,
905 mod_pd_notification_id_power_state_transition)) {
906 post_state_params =
907 (struct mod_pd_power_state_transition_notification_params *)
908 event->params;
909 if (post_state_params->state == MOD_PD_STATE_ON) {
910 group_ctx->pd_state_on = true;
911 }
912 } else {
913 return FWK_E_PARAM;
914 }
915
916 return FWK_SUCCESS;
917 }
918
919 const struct fwk_module module_juno_pvt = {
920 .type = FWK_MODULE_TYPE_DRIVER,
921 .api_count = 1,
922 .event_count = (unsigned int)JUNO_PVT_EVENT_IDX_COUNT,
923 .init = juno_pvt_init,
924 .element_init = juno_pvt_element_init,
925 .bind = juno_pvt_bind,
926 .process_bind_request = juno_pvt_process_bind_request,
927 .start = pvt_start,
928 .process_event = pvt_process_event,
929 .process_notification = pvt_process_notification,
930 };
931