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