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