1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <internal/n1sdp_scp2pcc.h>
9 
10 #include <mod_n1sdp_scp2pcc.h>
11 #include <mod_n1sdp_sensor.h>
12 #include <mod_n1sdp_sensor_driver.h>
13 #include <mod_power_domain.h>
14 #include <mod_sensor.h>
15 #include <mod_timer.h>
16 
17 #include <fwk_assert.h>
18 #include <fwk_id.h>
19 #include <fwk_log.h>
20 #include <fwk_mm.h>
21 #include <fwk_module.h>
22 #include <fwk_module_idx.h>
23 #include <fwk_status.h>
24 
25 /* N1SDP sensor driver information */
26 #define N1SDP_SENSOR_VERSION_MAJOR 1
27 #define N1SDP_SENSOR_VERSION_MINOR 1
28 
29 struct n1sdp_sensor_ctx sensor_ctx;
30 
n1sdp_sensor_timer_callback(uintptr_t unused)31 static void n1sdp_sensor_timer_callback(uintptr_t unused)
32 {
33     struct n1sdp_temp_sensor_ctx *t_dev_ctx;
34     struct n1sdp_volt_sensor_ctx *v_dev_ctx;
35     unsigned int count;
36     uint32_t status;
37     int32_t value;
38 
39     for (count = 0; count < sensor_ctx.module_config->t_sensor_count; count++) {
40         t_dev_ctx = &sensor_ctx.t_dev_ctx_table[count];
41         status = n1sdp_sensor_lib_sample(&value, MOD_N1SDP_TEMP_SENSOR, count);
42         if (status == FWK_SUCCESS) {
43             if (value >= t_dev_ctx->config->alarm_threshold &&
44                 value < t_dev_ctx->config->shutdown_threshold) {
45                 FWK_LOG_CRIT(
46                     "%s temperature (%d) reached alarm threshold!\n",
47                     sensor_type_name[count],
48                     (int)value);
49             } else if (value >= t_dev_ctx->config->shutdown_threshold) {
50                 FWK_LOG_CRIT(
51                     "%s temperature (%d) reached shutdown threshold!\n",
52                     sensor_type_name[count],
53                     (int)value);
54 
55                 status = sensor_ctx.scp2pcc_api->send(
56                     NULL, 0, SCP2PCC_TYPE_SHUTDOWN);
57             }
58 
59             t_dev_ctx->sensor_data_buffer[t_dev_ctx->buf_index++] = value;
60 
61             if (t_dev_ctx->buf_index == PVT_HISTORY_LEN) {
62                 t_dev_ctx->buf_index = 0;
63             }
64         }
65     }
66     /* Start new sample. */
67     n1sdp_sensor_lib_trigger_sample(MOD_N1SDP_TEMP_SENSOR);
68 
69     status = n1sdp_sensor_lib_sample(&value, MOD_N1SDP_VOLT_SENSOR, 0);
70     if (status == FWK_SUCCESS) {
71         for (count = 0; count < sensor_ctx.module_config->v_sensor_count;
72              count++) {
73             v_dev_ctx = &sensor_ctx.v_dev_ctx_table[count];
74             n1sdp_sensor_lib_sample(&value, MOD_N1SDP_VOLT_SENSOR, count);
75 
76             v_dev_ctx->sensor_data_buffer[v_dev_ctx->buf_index++] = value;
77 
78             if (v_dev_ctx->buf_index == PVT_HISTORY_LEN) {
79                 v_dev_ctx->buf_index = 0;
80             }
81         }
82     }
83     /* Start new sample. */
84     n1sdp_sensor_lib_trigger_sample(MOD_N1SDP_VOLT_SENSOR);
85 }
86 
87 /*
88  * Module API
89  */
get_value(fwk_id_t element_id,mod_sensor_value_t * value)90 static int get_value(fwk_id_t element_id, mod_sensor_value_t *value)
91 {
92 #ifdef BUILD_HAS_SENSOR_SIGNED_VALUE
93     return FWK_E_SUPPORT;
94 #else
95     struct n1sdp_temp_sensor_ctx *t_dev_ctx;
96     struct n1sdp_volt_sensor_ctx *v_dev_ctx;
97     unsigned int id;
98     uint8_t t_sensor_count, v_sensor_count;
99     int32_t buf_value;
100 
101     id = fwk_id_get_element_idx(element_id);
102     t_sensor_count = sensor_ctx.module_config->t_sensor_count;
103     v_sensor_count = sensor_ctx.module_config->v_sensor_count;
104 
105     if (id >= (t_sensor_count + v_sensor_count)) {
106         return FWK_E_PARAM;
107     }
108 
109     if (id < t_sensor_count) {
110         t_dev_ctx = &sensor_ctx.t_dev_ctx_table[id];
111         if (t_dev_ctx == NULL) {
112             return FWK_E_DATA;
113         }
114 
115         buf_value = t_dev_ctx->sensor_data_buffer
116                         [t_dev_ctx->buf_index == 0 ? PVT_HISTORY_LEN - 1 :
117                                                      t_dev_ctx->buf_index - 1];
118     } else {
119         v_dev_ctx = &sensor_ctx.v_dev_ctx_table[id - t_sensor_count];
120         if (v_dev_ctx == NULL) {
121             return FWK_E_DATA;
122         }
123 
124         buf_value = v_dev_ctx->sensor_data_buffer
125                         [v_dev_ctx->buf_index == 0 ? PVT_HISTORY_LEN - 1 :
126                                                      v_dev_ctx->buf_index - 1];
127     }
128     *value = (uint64_t)buf_value;
129 
130     return FWK_SUCCESS;
131 #endif
132 }
133 
get_info(fwk_id_t element_id,struct mod_sensor_info * info)134 static int get_info(fwk_id_t element_id, struct mod_sensor_info *info)
135 {
136     struct mod_sensor_info *return_info;
137     unsigned int id;
138     uint8_t t_sensor_count, v_sensor_count;
139     const struct mod_n1sdp_temp_sensor_config *t_config;
140     const struct mod_n1sdp_volt_sensor_config *v_config;
141 
142     id = fwk_id_get_element_idx(element_id);
143     t_sensor_count = sensor_ctx.module_config->t_sensor_count;
144     v_sensor_count = sensor_ctx.module_config->v_sensor_count;
145 
146     if (id >= (t_sensor_count + v_sensor_count)) {
147         return FWK_E_PARAM;
148     }
149 
150     if (id < t_sensor_count) {
151         t_config = fwk_module_get_data(element_id);
152         return_info = t_config->info;
153     } else {
154         v_config = fwk_module_get_data(element_id);
155         return_info = v_config->info;
156     }
157 
158     if (!fwk_expect(return_info != NULL)) {
159         return FWK_E_DATA;
160     }
161 
162     *info = *return_info;
163 
164     return FWK_SUCCESS;
165 }
166 
167 static const struct mod_sensor_driver_api n1sdp_sensor_api = {
168     .get_value = get_value,
169     .get_info = get_info,
170 };
171 
172 /*
173  * Framework handlers
174  */
n1sdp_sensor_init(fwk_id_t module_id,unsigned int element_count,const void * data)175 static int n1sdp_sensor_init(
176     fwk_id_t module_id,
177     unsigned int element_count,
178     const void *data)
179 {
180     fwk_assert(data != NULL);
181 
182     if (element_count == 0) {
183         return FWK_E_DATA;
184     }
185 
186     sensor_ctx.module_config = (struct mod_n1sdp_sensor_config *)data;
187 
188     sensor_ctx.t_dev_ctx_table = fwk_mm_calloc(
189         sensor_ctx.module_config->t_sensor_count,
190         sizeof(sensor_ctx.t_dev_ctx_table[0]));
191 
192     if (sensor_ctx.t_dev_ctx_table == NULL) {
193         return FWK_E_NOMEM;
194     }
195 
196     sensor_ctx.v_dev_ctx_table = fwk_mm_calloc(
197         sensor_ctx.module_config->v_sensor_count,
198         sizeof(sensor_ctx.v_dev_ctx_table[0]));
199 
200     if (sensor_ctx.v_dev_ctx_table == NULL) {
201         return FWK_E_NOMEM;
202     }
203 
204     return FWK_SUCCESS;
205 }
206 
n1sdp_sensor_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)207 static int n1sdp_sensor_element_init(
208     fwk_id_t element_id,
209     unsigned int sub_element_count,
210     const void *data)
211 {
212     struct n1sdp_temp_sensor_ctx *t_dev_ctx;
213     struct n1sdp_volt_sensor_ctx *v_dev_ctx;
214     struct mod_n1sdp_temp_sensor_config *t_config;
215     struct mod_n1sdp_volt_sensor_config *v_config;
216     unsigned int id;
217     uint8_t t_sensor_count;
218 
219     fwk_assert(data != NULL);
220     id = fwk_id_get_element_idx(element_id);
221     t_sensor_count = sensor_ctx.module_config->t_sensor_count;
222 
223     if (id < t_sensor_count) {
224         t_config = (struct mod_n1sdp_temp_sensor_config *)data;
225 
226         t_dev_ctx = &sensor_ctx.t_dev_ctx_table[id];
227         if (t_dev_ctx == NULL) {
228             return FWK_E_DATA;
229         }
230 
231         t_dev_ctx->config = t_config;
232 
233         t_dev_ctx->sensor_data_buffer =
234             fwk_mm_calloc(PVT_HISTORY_LEN, sizeof(int32_t));
235         if (t_dev_ctx->sensor_data_buffer == NULL) {
236             return FWK_E_NOMEM;
237         }
238 
239         t_dev_ctx->buf_index = 0;
240     } else {
241         v_config = (struct mod_n1sdp_volt_sensor_config *)data;
242 
243         v_dev_ctx = &sensor_ctx.v_dev_ctx_table[id - t_sensor_count];
244         if (v_dev_ctx == NULL) {
245             return FWK_E_DATA;
246         }
247 
248         v_dev_ctx->config = v_config;
249 
250         v_dev_ctx->sensor_data_buffer =
251             fwk_mm_calloc(PVT_HISTORY_LEN, sizeof(int32_t));
252         if (v_dev_ctx->sensor_data_buffer == NULL) {
253             return FWK_E_NOMEM;
254         }
255 
256         v_dev_ctx->buf_index = 0;
257     }
258 
259     return FWK_SUCCESS;
260 }
261 
n1sdp_sensor_bind(fwk_id_t id,unsigned int round)262 static int n1sdp_sensor_bind(fwk_id_t id, unsigned int round)
263 {
264     int status;
265 
266     if (round == 0) {
267         if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
268             status = fwk_module_bind(
269                 sensor_ctx.module_config->alarm_id,
270                 sensor_ctx.module_config->alarm_api,
271                 &sensor_ctx.timer_alarm_api);
272 
273             if (status != FWK_SUCCESS) {
274                 return status;
275             }
276 
277             status = fwk_module_bind(
278                 FWK_ID_MODULE(FWK_MODULE_IDX_N1SDP_SCP2PCC),
279                 FWK_ID_API(FWK_MODULE_IDX_N1SDP_SCP2PCC, 0),
280                 &sensor_ctx.scp2pcc_api);
281             if (status != FWK_SUCCESS) {
282                 return status;
283             }
284         }
285     }
286     return FWK_SUCCESS;
287 }
288 
n1sdp_sensor_start(fwk_id_t id)289 static int n1sdp_sensor_start(fwk_id_t id)
290 {
291     int status;
292     uint32_t error_reg;
293 
294     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
295         status = n1sdp_sensor_lib_init(&error_reg);
296         switch (status) {
297         case FWK_E_DEVICE:
298             FWK_LOG_INFO("[PVT] ID invalid: 0x%08X\n", (unsigned int)error_reg);
299             return FWK_E_DEVICE;
300         case FWK_E_DATA:
301             FWK_LOG_INFO(
302                 "[PVT] Scratch test failed: 0x%08X\n", (unsigned int)error_reg);
303             return FWK_E_DEVICE;
304         case FWK_E_TIMEOUT:
305             FWK_LOG_INFO("[PVT] Timeout waiting for sensor initialization!\n");
306             return FWK_E_TIMEOUT;
307         }
308 
309         status = sensor_ctx.timer_alarm_api->start(
310             sensor_ctx.module_config->alarm_id,
311             1000,
312             MOD_TIMER_ALARM_TYPE_PERIODIC,
313             &n1sdp_sensor_timer_callback,
314             0);
315 
316         if (status != FWK_SUCCESS) {
317             return status;
318         }
319 
320         FWK_LOG_INFO(
321             "[PVT] Started driver version %d.%d\n",
322             N1SDP_SENSOR_VERSION_MAJOR,
323             N1SDP_SENSOR_VERSION_MINOR);
324     }
325     return FWK_SUCCESS;
326 }
327 
n1sdp_sensor_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_type,const void ** api)328 static int n1sdp_sensor_process_bind_request(
329     fwk_id_t source_id,
330     fwk_id_t target_id,
331     fwk_id_t api_type,
332     const void **api)
333 {
334     *api = &n1sdp_sensor_api;
335     return FWK_SUCCESS;
336 }
337 
338 const struct fwk_module module_n1sdp_sensor = {
339     .api_count = 1,
340     .type = FWK_MODULE_TYPE_DRIVER,
341     .init = n1sdp_sensor_init,
342     .element_init = n1sdp_sensor_element_init,
343     .bind = n1sdp_sensor_bind,
344     .start = n1sdp_sensor_start,
345     .process_bind_request = n1sdp_sensor_process_bind_request,
346 };
347