]>
Commit | Line | Data |
---|---|---|
09c2845e SV |
1 | /* |
2 | * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. | |
3 | * Copyright (C) 2017 Linaro Ltd. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 and | |
7 | * only version 2 as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | */ | |
15 | #include <linux/hash.h> | |
16 | #include <linux/list.h> | |
17 | #include <linux/slab.h> | |
18 | #include <media/videobuf2-v4l2.h> | |
19 | ||
20 | #include "core.h" | |
21 | #include "hfi.h" | |
22 | #include "hfi_helper.h" | |
23 | #include "hfi_msgs.h" | |
24 | ||
25 | static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, | |
26 | struct hfi_msg_event_notify_pkt *pkt) | |
27 | { | |
28 | struct hfi_event_data event = {0}; | |
29 | int num_properties_changed; | |
30 | struct hfi_framesize *frame_sz; | |
31 | struct hfi_profile_level *profile_level; | |
32 | u8 *data_ptr; | |
33 | u32 ptype; | |
34 | ||
35 | inst->error = HFI_ERR_NONE; | |
36 | ||
37 | switch (pkt->event_data1) { | |
38 | case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES: | |
39 | case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES: | |
40 | break; | |
41 | default: | |
42 | inst->error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
43 | goto done; | |
44 | } | |
45 | ||
46 | event.event_type = pkt->event_data1; | |
47 | ||
48 | num_properties_changed = pkt->event_data2; | |
49 | if (!num_properties_changed) { | |
50 | inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
51 | goto done; | |
52 | } | |
53 | ||
54 | data_ptr = (u8 *)&pkt->ext_event_data[0]; | |
55 | do { | |
56 | ptype = *((u32 *)data_ptr); | |
57 | switch (ptype) { | |
58 | case HFI_PROPERTY_PARAM_FRAME_SIZE: | |
59 | data_ptr += sizeof(u32); | |
60 | frame_sz = (struct hfi_framesize *)data_ptr; | |
61 | event.width = frame_sz->width; | |
62 | event.height = frame_sz->height; | |
63 | data_ptr += sizeof(frame_sz); | |
64 | break; | |
65 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: | |
66 | data_ptr += sizeof(u32); | |
67 | profile_level = (struct hfi_profile_level *)data_ptr; | |
68 | event.profile = profile_level->profile; | |
69 | event.level = profile_level->level; | |
70 | data_ptr += sizeof(profile_level); | |
71 | break; | |
72 | default: | |
73 | break; | |
74 | } | |
75 | num_properties_changed--; | |
76 | } while (num_properties_changed > 0); | |
77 | ||
78 | done: | |
79 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
80 | } | |
81 | ||
82 | static void event_release_buffer_ref(struct venus_core *core, | |
83 | struct venus_inst *inst, | |
84 | struct hfi_msg_event_notify_pkt *pkt) | |
85 | { | |
86 | struct hfi_event_data event = {0}; | |
87 | struct hfi_msg_event_release_buffer_ref_pkt *data; | |
88 | ||
89 | data = (struct hfi_msg_event_release_buffer_ref_pkt *) | |
90 | pkt->ext_event_data; | |
91 | ||
92 | event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE; | |
93 | event.packet_buffer = data->packet_buffer; | |
94 | event.extradata_buffer = data->extradata_buffer; | |
95 | event.tag = data->output_tag; | |
96 | ||
97 | inst->error = HFI_ERR_NONE; | |
98 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
99 | } | |
100 | ||
101 | static void event_sys_error(struct venus_core *core, u32 event, | |
102 | struct hfi_msg_event_notify_pkt *pkt) | |
103 | { | |
104 | if (pkt) | |
105 | dev_dbg(core->dev, | |
106 | "sys error (session id:%x, data1:%x, data2:%x)\n", | |
107 | pkt->shdr.session_id, pkt->event_data1, | |
108 | pkt->event_data2); | |
109 | ||
110 | core->core_ops->event_notify(core, event); | |
111 | } | |
112 | ||
113 | static void | |
114 | event_session_error(struct venus_core *core, struct venus_inst *inst, | |
115 | struct hfi_msg_event_notify_pkt *pkt) | |
116 | { | |
117 | struct device *dev = core->dev; | |
118 | ||
119 | dev_dbg(dev, "session error: event id:%x, session id:%x\n", | |
120 | pkt->event_data1, pkt->shdr.session_id); | |
121 | ||
122 | if (!inst) | |
123 | return; | |
124 | ||
125 | switch (pkt->event_data1) { | |
126 | /* non fatal session errors */ | |
127 | case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: | |
128 | case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE: | |
129 | case HFI_ERR_SESSION_UNSUPPORTED_SETTING: | |
130 | case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: | |
131 | inst->error = HFI_ERR_NONE; | |
132 | break; | |
133 | default: | |
134 | dev_err(dev, "session error: event id:%x (%x), session id:%x\n", | |
135 | pkt->event_data1, pkt->event_data2, | |
136 | pkt->shdr.session_id); | |
137 | ||
138 | inst->error = pkt->event_data1; | |
139 | inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); | |
140 | break; | |
141 | } | |
142 | } | |
143 | ||
144 | static void hfi_event_notify(struct venus_core *core, struct venus_inst *inst, | |
145 | void *packet) | |
146 | { | |
147 | struct hfi_msg_event_notify_pkt *pkt = packet; | |
148 | ||
149 | if (!packet) | |
150 | return; | |
151 | ||
152 | switch (pkt->event_id) { | |
153 | case HFI_EVENT_SYS_ERROR: | |
154 | event_sys_error(core, EVT_SYS_ERROR, pkt); | |
155 | break; | |
156 | case HFI_EVENT_SESSION_ERROR: | |
157 | event_session_error(core, inst, pkt); | |
158 | break; | |
159 | case HFI_EVENT_SESSION_SEQUENCE_CHANGED: | |
160 | event_seq_changed(core, inst, pkt); | |
161 | break; | |
162 | case HFI_EVENT_RELEASE_BUFFER_REFERENCE: | |
163 | event_release_buffer_ref(core, inst, pkt); | |
164 | break; | |
165 | case HFI_EVENT_SESSION_PROPERTY_CHANGED: | |
166 | break; | |
167 | default: | |
168 | break; | |
169 | } | |
170 | } | |
171 | ||
172 | static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst, | |
173 | void *packet) | |
174 | { | |
175 | struct hfi_msg_sys_init_done_pkt *pkt = packet; | |
176 | u32 rem_bytes, read_bytes = 0, num_properties; | |
177 | u32 error, ptype; | |
178 | u8 *data; | |
179 | ||
180 | error = pkt->error_type; | |
181 | if (error != HFI_ERR_NONE) | |
182 | goto err_no_prop; | |
183 | ||
184 | num_properties = pkt->num_properties; | |
185 | ||
186 | if (!num_properties) { | |
187 | error = HFI_ERR_SYS_INVALID_PARAMETER; | |
188 | goto err_no_prop; | |
189 | } | |
190 | ||
191 | rem_bytes = pkt->hdr.size - sizeof(*pkt) + sizeof(u32); | |
192 | ||
193 | if (!rem_bytes) { | |
194 | /* missing property data */ | |
195 | error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES; | |
196 | goto err_no_prop; | |
197 | } | |
198 | ||
199 | data = (u8 *)&pkt->data[0]; | |
200 | ||
201 | if (core->res->hfi_version == HFI_VERSION_3XX) | |
202 | goto err_no_prop; | |
203 | ||
204 | while (num_properties && rem_bytes >= sizeof(u32)) { | |
205 | ptype = *((u32 *)data); | |
206 | data += sizeof(u32); | |
207 | ||
208 | switch (ptype) { | |
209 | case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: { | |
210 | struct hfi_codec_supported *prop; | |
211 | ||
212 | prop = (struct hfi_codec_supported *)data; | |
213 | ||
214 | if (rem_bytes < sizeof(*prop)) { | |
215 | error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES; | |
216 | break; | |
217 | } | |
218 | ||
219 | read_bytes += sizeof(*prop) + sizeof(u32); | |
220 | core->dec_codecs = prop->dec_codecs; | |
221 | core->enc_codecs = prop->enc_codecs; | |
222 | break; | |
223 | } | |
224 | case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED: { | |
225 | struct hfi_max_sessions_supported *prop; | |
226 | ||
227 | if (rem_bytes < sizeof(*prop)) { | |
228 | error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES; | |
229 | break; | |
230 | } | |
231 | ||
232 | prop = (struct hfi_max_sessions_supported *)data; | |
233 | read_bytes += sizeof(*prop) + sizeof(u32); | |
234 | core->max_sessions_supported = prop->max_sessions; | |
235 | break; | |
236 | } | |
237 | default: | |
238 | error = HFI_ERR_SYS_INVALID_PARAMETER; | |
239 | break; | |
240 | } | |
241 | ||
3e7caae5 RC |
242 | if (error) |
243 | break; | |
244 | ||
245 | rem_bytes -= read_bytes; | |
246 | data += read_bytes; | |
247 | num_properties--; | |
09c2845e SV |
248 | } |
249 | ||
250 | err_no_prop: | |
251 | core->error = error; | |
252 | complete(&core->done); | |
253 | } | |
254 | ||
255 | static void | |
256 | sys_get_prop_image_version(struct device *dev, | |
257 | struct hfi_msg_sys_property_info_pkt *pkt) | |
258 | { | |
259 | int req_bytes; | |
260 | ||
261 | req_bytes = pkt->hdr.size - sizeof(*pkt); | |
262 | ||
263 | if (req_bytes < 128 || !pkt->data[1] || pkt->num_properties > 1) | |
264 | /* bad packet */ | |
265 | return; | |
266 | ||
267 | dev_dbg(dev, "F/W version: %s\n", (u8 *)&pkt->data[1]); | |
268 | } | |
269 | ||
270 | static void hfi_sys_property_info(struct venus_core *core, | |
271 | struct venus_inst *inst, void *packet) | |
272 | { | |
273 | struct hfi_msg_sys_property_info_pkt *pkt = packet; | |
274 | struct device *dev = core->dev; | |
275 | ||
276 | if (!pkt->num_properties) { | |
277 | dev_dbg(dev, "%s: no properties\n", __func__); | |
278 | return; | |
279 | } | |
280 | ||
281 | switch (pkt->data[0]) { | |
282 | case HFI_PROPERTY_SYS_IMAGE_VERSION: | |
283 | sys_get_prop_image_version(dev, pkt); | |
284 | break; | |
285 | default: | |
286 | dev_dbg(dev, "%s: unknown property data\n", __func__); | |
287 | break; | |
288 | } | |
289 | } | |
290 | ||
291 | static void hfi_sys_rel_resource_done(struct venus_core *core, | |
292 | struct venus_inst *inst, | |
293 | void *packet) | |
294 | { | |
295 | struct hfi_msg_sys_release_resource_done_pkt *pkt = packet; | |
296 | ||
297 | core->error = pkt->error_type; | |
298 | complete(&core->done); | |
299 | } | |
300 | ||
301 | static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst, | |
302 | void *packet) | |
303 | { | |
304 | struct hfi_msg_sys_ping_ack_pkt *pkt = packet; | |
305 | ||
306 | core->error = HFI_ERR_NONE; | |
307 | ||
308 | if (pkt->client_data != 0xbeef) | |
309 | core->error = HFI_ERR_SYS_FATAL; | |
310 | ||
311 | complete(&core->done); | |
312 | } | |
313 | ||
314 | static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst, | |
315 | void *packet) | |
316 | { | |
317 | dev_dbg(core->dev, "sys idle\n"); | |
318 | } | |
319 | ||
320 | static void hfi_sys_pc_prepare_done(struct venus_core *core, | |
321 | struct venus_inst *inst, void *packet) | |
322 | { | |
323 | struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet; | |
324 | ||
325 | dev_dbg(core->dev, "pc prepare done (error %x)\n", pkt->error_type); | |
326 | } | |
327 | ||
328 | static void | |
329 | hfi_copy_cap_prop(struct hfi_capability *in, struct venus_inst *inst) | |
330 | { | |
331 | if (!in || !inst) | |
332 | return; | |
333 | ||
334 | switch (in->capability_type) { | |
335 | case HFI_CAPABILITY_FRAME_WIDTH: | |
336 | inst->cap_width = *in; | |
337 | break; | |
338 | case HFI_CAPABILITY_FRAME_HEIGHT: | |
339 | inst->cap_height = *in; | |
340 | break; | |
341 | case HFI_CAPABILITY_MBS_PER_FRAME: | |
342 | inst->cap_mbs_per_frame = *in; | |
343 | break; | |
344 | case HFI_CAPABILITY_MBS_PER_SECOND: | |
345 | inst->cap_mbs_per_sec = *in; | |
346 | break; | |
347 | case HFI_CAPABILITY_FRAMERATE: | |
348 | inst->cap_framerate = *in; | |
349 | break; | |
350 | case HFI_CAPABILITY_SCALE_X: | |
351 | inst->cap_scale_x = *in; | |
352 | break; | |
353 | case HFI_CAPABILITY_SCALE_Y: | |
354 | inst->cap_scale_y = *in; | |
355 | break; | |
356 | case HFI_CAPABILITY_BITRATE: | |
357 | inst->cap_bitrate = *in; | |
358 | break; | |
359 | case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: | |
360 | inst->cap_hier_p = *in; | |
361 | break; | |
362 | case HFI_CAPABILITY_ENC_LTR_COUNT: | |
363 | inst->cap_ltr_count = *in; | |
364 | break; | |
365 | case HFI_CAPABILITY_CP_OUTPUT2_THRESH: | |
366 | inst->cap_secure_output2_threshold = *in; | |
367 | break; | |
368 | default: | |
369 | break; | |
370 | } | |
371 | } | |
372 | ||
373 | static unsigned int | |
374 | session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt, | |
375 | struct hfi_profile_level *profile_level) | |
376 | { | |
377 | struct hfi_profile_level *hfi; | |
378 | u32 req_bytes; | |
379 | ||
380 | req_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | |
381 | ||
382 | if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) | |
383 | /* bad packet */ | |
384 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
385 | ||
386 | hfi = (struct hfi_profile_level *)&pkt->data[1]; | |
387 | profile_level->profile = hfi->profile; | |
388 | profile_level->level = hfi->level; | |
389 | ||
390 | return HFI_ERR_NONE; | |
391 | } | |
392 | ||
393 | static unsigned int | |
394 | session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt, | |
395 | struct hfi_buffer_requirements *bufreq) | |
396 | { | |
397 | struct hfi_buffer_requirements *buf_req; | |
398 | u32 req_bytes; | |
399 | unsigned int idx = 0; | |
400 | ||
401 | req_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | |
402 | ||
403 | if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1]) | |
404 | /* bad packet */ | |
405 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
406 | ||
407 | buf_req = (struct hfi_buffer_requirements *)&pkt->data[1]; | |
408 | if (!buf_req) | |
409 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
410 | ||
411 | while (req_bytes) { | |
412 | memcpy(&bufreq[idx], buf_req, sizeof(*bufreq)); | |
413 | idx++; | |
414 | ||
415 | if (idx > HFI_BUFFER_TYPE_MAX) | |
416 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
417 | ||
418 | req_bytes -= sizeof(struct hfi_buffer_requirements); | |
419 | buf_req++; | |
420 | } | |
421 | ||
422 | return HFI_ERR_NONE; | |
423 | } | |
424 | ||
425 | static void hfi_session_prop_info(struct venus_core *core, | |
426 | struct venus_inst *inst, void *packet) | |
427 | { | |
428 | struct hfi_msg_session_property_info_pkt *pkt = packet; | |
429 | struct device *dev = core->dev; | |
430 | union hfi_get_property *hprop = &inst->hprop; | |
431 | unsigned int error = HFI_ERR_NONE; | |
432 | ||
433 | if (!pkt->num_properties) { | |
434 | error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
435 | dev_err(dev, "%s: no properties\n", __func__); | |
436 | goto done; | |
437 | } | |
438 | ||
439 | switch (pkt->data[0]) { | |
440 | case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: | |
441 | memset(hprop->bufreq, 0, sizeof(hprop->bufreq)); | |
442 | error = session_get_prop_buf_req(pkt, hprop->bufreq); | |
443 | break; | |
444 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: | |
445 | memset(&hprop->profile_level, 0, sizeof(hprop->profile_level)); | |
446 | error = session_get_prop_profile_level(pkt, | |
447 | &hprop->profile_level); | |
448 | break; | |
449 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: | |
450 | break; | |
451 | default: | |
452 | dev_dbg(dev, "%s: unknown property id:%x\n", __func__, | |
453 | pkt->data[0]); | |
454 | return; | |
455 | } | |
456 | ||
457 | done: | |
458 | inst->error = error; | |
459 | complete(&inst->done); | |
460 | } | |
461 | ||
462 | static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst, | |
463 | struct hfi_msg_session_init_done_pkt *pkt) | |
464 | { | |
465 | struct device *dev = core->dev; | |
832d4671 | 466 | u32 rem_bytes, num_props; |
09c2845e SV |
467 | u32 ptype, next_offset = 0; |
468 | u32 err; | |
469 | u8 *data; | |
470 | ||
471 | rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt) + sizeof(u32); | |
472 | if (!rem_bytes) { | |
473 | dev_err(dev, "%s: missing property info\n", __func__); | |
474 | return HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
475 | } | |
476 | ||
477 | err = pkt->error_type; | |
478 | if (err) | |
479 | return err; | |
480 | ||
481 | data = (u8 *)&pkt->data[0]; | |
482 | num_props = pkt->num_properties; | |
483 | ||
484 | while (err == HFI_ERR_NONE && num_props && rem_bytes >= sizeof(u32)) { | |
485 | ptype = *((u32 *)data); | |
486 | next_offset = sizeof(u32); | |
487 | ||
488 | switch (ptype) { | |
489 | case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: { | |
490 | struct hfi_codec_mask_supported *masks = | |
491 | (struct hfi_codec_mask_supported *) | |
492 | (data + next_offset); | |
493 | ||
09c2845e SV |
494 | next_offset += sizeof(*masks); |
495 | num_props--; | |
496 | break; | |
497 | } | |
498 | case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: { | |
499 | struct hfi_capabilities *caps; | |
500 | struct hfi_capability *cap; | |
501 | u32 num_caps; | |
502 | ||
503 | if ((rem_bytes - next_offset) < sizeof(*cap)) { | |
504 | err = HFI_ERR_SESSION_INVALID_PARAMETER; | |
505 | break; | |
506 | } | |
507 | ||
508 | caps = (struct hfi_capabilities *)(data + next_offset); | |
509 | ||
510 | num_caps = caps->num_capabilities; | |
511 | cap = &caps->data[0]; | |
512 | next_offset += sizeof(u32); | |
513 | ||
514 | while (num_caps && | |
515 | (rem_bytes - next_offset) >= sizeof(u32)) { | |
516 | hfi_copy_cap_prop(cap, inst); | |
517 | cap++; | |
518 | next_offset += sizeof(*cap); | |
519 | num_caps--; | |
520 | } | |
521 | num_props--; | |
522 | break; | |
523 | } | |
524 | case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: { | |
525 | struct hfi_uncompressed_format_supported *prop = | |
526 | (struct hfi_uncompressed_format_supported *) | |
527 | (data + next_offset); | |
528 | u32 num_fmt_entries; | |
529 | u8 *fmt; | |
530 | struct hfi_uncompressed_plane_info *inf; | |
531 | ||
532 | if ((rem_bytes - next_offset) < sizeof(*prop)) { | |
533 | err = HFI_ERR_SESSION_INVALID_PARAMETER; | |
534 | break; | |
535 | } | |
536 | ||
537 | num_fmt_entries = prop->format_entries; | |
538 | next_offset = sizeof(*prop) - sizeof(u32); | |
539 | fmt = (u8 *)&prop->format_info[0]; | |
540 | ||
541 | dev_dbg(dev, "uncomm format support num entries:%u\n", | |
542 | num_fmt_entries); | |
543 | ||
544 | while (num_fmt_entries) { | |
545 | struct hfi_uncompressed_plane_constraints *cnts; | |
546 | u32 bytes_to_skip; | |
547 | ||
548 | inf = (struct hfi_uncompressed_plane_info *)fmt; | |
549 | ||
550 | if ((rem_bytes - next_offset) < sizeof(*inf)) { | |
551 | err = HFI_ERR_SESSION_INVALID_PARAMETER; | |
552 | break; | |
553 | } | |
554 | ||
555 | dev_dbg(dev, "plane info: fmt:%x, planes:%x\n", | |
556 | inf->format, inf->num_planes); | |
557 | ||
558 | cnts = &inf->plane_format[0]; | |
559 | dev_dbg(dev, "%u %u %u %u\n", | |
560 | cnts->stride_multiples, | |
561 | cnts->max_stride, | |
562 | cnts->min_plane_buffer_height_multiple, | |
563 | cnts->buffer_alignment); | |
564 | ||
565 | bytes_to_skip = sizeof(*inf) - sizeof(*cnts) + | |
566 | inf->num_planes * sizeof(*cnts); | |
567 | ||
568 | fmt += bytes_to_skip; | |
569 | next_offset += bytes_to_skip; | |
570 | num_fmt_entries--; | |
571 | } | |
572 | num_props--; | |
573 | break; | |
574 | } | |
575 | case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: { | |
576 | struct hfi_properties_supported *prop = | |
577 | (struct hfi_properties_supported *) | |
578 | (data + next_offset); | |
579 | ||
580 | next_offset += sizeof(*prop) - sizeof(u32) | |
581 | + prop->num_properties * sizeof(u32); | |
582 | num_props--; | |
583 | break; | |
584 | } | |
585 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: { | |
586 | struct hfi_profile_level_supported *prop = | |
587 | (struct hfi_profile_level_supported *) | |
588 | (data + next_offset); | |
589 | struct hfi_profile_level *pl; | |
590 | unsigned int prop_count = 0; | |
591 | unsigned int count = 0; | |
592 | u8 *ptr; | |
593 | ||
594 | ptr = (u8 *)&prop->profile_level[0]; | |
595 | prop_count = prop->profile_count; | |
596 | ||
597 | if (prop_count > HFI_MAX_PROFILE_COUNT) | |
598 | prop_count = HFI_MAX_PROFILE_COUNT; | |
599 | ||
600 | while (prop_count) { | |
601 | ptr++; | |
602 | pl = (struct hfi_profile_level *)ptr; | |
603 | ||
604 | inst->pl[count].profile = pl->profile; | |
605 | inst->pl[count].level = pl->level; | |
606 | prop_count--; | |
607 | count++; | |
608 | ptr += sizeof(*pl) / sizeof(u32); | |
609 | } | |
610 | ||
611 | inst->pl_count = count; | |
612 | next_offset += sizeof(*prop) - sizeof(*pl) + | |
613 | prop->profile_count * sizeof(*pl); | |
614 | ||
615 | num_props--; | |
616 | break; | |
617 | } | |
618 | case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: { | |
619 | next_offset += | |
620 | sizeof(struct hfi_interlace_format_supported); | |
621 | num_props--; | |
622 | break; | |
623 | } | |
624 | case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: { | |
625 | struct hfi_nal_stream_format *nal = | |
626 | (struct hfi_nal_stream_format *) | |
627 | (data + next_offset); | |
628 | dev_dbg(dev, "NAL format: %x\n", nal->format); | |
629 | next_offset += sizeof(*nal); | |
630 | num_props--; | |
631 | break; | |
632 | } | |
633 | case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { | |
634 | next_offset += sizeof(u32); | |
635 | num_props--; | |
636 | break; | |
637 | } | |
638 | case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: { | |
639 | u32 *max_seq_sz = (u32 *)(data + next_offset); | |
640 | ||
641 | dev_dbg(dev, "max seq header sz: %x\n", *max_seq_sz); | |
642 | next_offset += sizeof(u32); | |
643 | num_props--; | |
644 | break; | |
645 | } | |
646 | case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { | |
647 | next_offset += sizeof(struct hfi_intra_refresh); | |
648 | num_props--; | |
649 | break; | |
650 | } | |
651 | case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: { | |
652 | struct hfi_buffer_alloc_mode_supported *prop = | |
653 | (struct hfi_buffer_alloc_mode_supported *) | |
654 | (data + next_offset); | |
655 | unsigned int i; | |
656 | ||
657 | for (i = 0; i < prop->num_entries; i++) { | |
658 | if (prop->buffer_type == HFI_BUFFER_OUTPUT || | |
659 | prop->buffer_type == HFI_BUFFER_OUTPUT2) { | |
660 | switch (prop->data[i]) { | |
661 | case HFI_BUFFER_MODE_STATIC: | |
662 | inst->cap_bufs_mode_static = 1; | |
663 | break; | |
664 | case HFI_BUFFER_MODE_DYNAMIC: | |
665 | inst->cap_bufs_mode_dynamic = 1; | |
666 | break; | |
667 | default: | |
668 | break; | |
669 | } | |
670 | } | |
671 | } | |
672 | next_offset += sizeof(*prop) - | |
673 | sizeof(u32) + prop->num_entries * sizeof(u32); | |
674 | num_props--; | |
675 | break; | |
676 | } | |
677 | default: | |
678 | dev_dbg(dev, "%s: default case %#x\n", __func__, ptype); | |
679 | break; | |
680 | } | |
681 | ||
682 | rem_bytes -= next_offset; | |
683 | data += next_offset; | |
684 | } | |
685 | ||
686 | return err; | |
687 | } | |
688 | ||
689 | static void hfi_session_init_done(struct venus_core *core, | |
690 | struct venus_inst *inst, void *packet) | |
691 | { | |
692 | struct hfi_msg_session_init_done_pkt *pkt = packet; | |
693 | unsigned int error; | |
694 | ||
695 | error = pkt->error_type; | |
696 | if (error != HFI_ERR_NONE) | |
697 | goto done; | |
698 | ||
699 | if (core->res->hfi_version != HFI_VERSION_1XX) | |
700 | goto done; | |
701 | ||
702 | error = init_done_read_prop(core, inst, pkt); | |
703 | ||
704 | done: | |
705 | inst->error = error; | |
706 | complete(&inst->done); | |
707 | } | |
708 | ||
709 | static void hfi_session_load_res_done(struct venus_core *core, | |
710 | struct venus_inst *inst, void *packet) | |
711 | { | |
712 | struct hfi_msg_session_load_resources_done_pkt *pkt = packet; | |
713 | ||
714 | inst->error = pkt->error_type; | |
715 | complete(&inst->done); | |
716 | } | |
717 | ||
718 | static void hfi_session_flush_done(struct venus_core *core, | |
719 | struct venus_inst *inst, void *packet) | |
720 | { | |
721 | struct hfi_msg_session_flush_done_pkt *pkt = packet; | |
722 | ||
723 | inst->error = pkt->error_type; | |
724 | complete(&inst->done); | |
725 | } | |
726 | ||
727 | static void hfi_session_etb_done(struct venus_core *core, | |
728 | struct venus_inst *inst, void *packet) | |
729 | { | |
730 | struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet; | |
731 | ||
732 | inst->error = pkt->error_type; | |
733 | inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag, | |
734 | pkt->filled_len, pkt->offset, 0, 0, 0); | |
735 | } | |
736 | ||
737 | static void hfi_session_ftb_done(struct venus_core *core, | |
738 | struct venus_inst *inst, void *packet) | |
739 | { | |
740 | u32 session_type = inst->session_type; | |
741 | u64 timestamp_us = 0; | |
742 | u32 timestamp_hi = 0, timestamp_lo = 0; | |
743 | unsigned int error; | |
744 | u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0; | |
745 | u32 pic_type = 0, buffer_type = 0, output_tag = -1; | |
746 | ||
747 | if (session_type == VIDC_SESSION_TYPE_ENC) { | |
748 | struct hfi_msg_session_fbd_compressed_pkt *pkt = packet; | |
749 | ||
750 | timestamp_hi = pkt->time_stamp_hi; | |
751 | timestamp_lo = pkt->time_stamp_lo; | |
752 | hfi_flags = pkt->flags; | |
753 | offset = pkt->offset; | |
754 | filled_len = pkt->filled_len; | |
755 | pic_type = pkt->picture_type; | |
756 | output_tag = pkt->output_tag; | |
757 | buffer_type = HFI_BUFFER_OUTPUT; | |
758 | ||
759 | error = pkt->error_type; | |
760 | } else if (session_type == VIDC_SESSION_TYPE_DEC) { | |
761 | struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt = | |
762 | packet; | |
763 | ||
764 | timestamp_hi = pkt->time_stamp_hi; | |
765 | timestamp_lo = pkt->time_stamp_lo; | |
766 | hfi_flags = pkt->flags; | |
767 | offset = pkt->offset; | |
768 | filled_len = pkt->filled_len; | |
769 | pic_type = pkt->picture_type; | |
770 | output_tag = pkt->output_tag; | |
771 | ||
772 | if (pkt->stream_id == 0) | |
773 | buffer_type = HFI_BUFFER_OUTPUT; | |
774 | else if (pkt->stream_id == 1) | |
775 | buffer_type = HFI_BUFFER_OUTPUT2; | |
776 | ||
777 | error = pkt->error_type; | |
778 | } else { | |
779 | error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
780 | } | |
781 | ||
782 | if (buffer_type != HFI_BUFFER_OUTPUT) | |
783 | goto done; | |
784 | ||
785 | if (hfi_flags & HFI_BUFFERFLAG_EOS) | |
786 | flags |= V4L2_BUF_FLAG_LAST; | |
787 | ||
788 | switch (pic_type) { | |
789 | case HFI_PICTURE_IDR: | |
790 | case HFI_PICTURE_I: | |
791 | flags |= V4L2_BUF_FLAG_KEYFRAME; | |
792 | break; | |
793 | case HFI_PICTURE_P: | |
794 | flags |= V4L2_BUF_FLAG_PFRAME; | |
795 | break; | |
796 | case HFI_PICTURE_B: | |
797 | flags |= V4L2_BUF_FLAG_BFRAME; | |
798 | break; | |
799 | case HFI_FRAME_NOTCODED: | |
800 | case HFI_UNUSED_PICT: | |
801 | case HFI_FRAME_YUV: | |
802 | default: | |
803 | break; | |
804 | } | |
805 | ||
806 | if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) { | |
807 | timestamp_us = timestamp_hi; | |
808 | timestamp_us = (timestamp_us << 32) | timestamp_lo; | |
809 | } | |
810 | ||
811 | done: | |
812 | inst->error = error; | |
813 | inst->ops->buf_done(inst, buffer_type, output_tag, filled_len, | |
814 | offset, flags, hfi_flags, timestamp_us); | |
815 | } | |
816 | ||
817 | static void hfi_session_start_done(struct venus_core *core, | |
818 | struct venus_inst *inst, void *packet) | |
819 | { | |
820 | struct hfi_msg_session_start_done_pkt *pkt = packet; | |
821 | ||
822 | inst->error = pkt->error_type; | |
823 | complete(&inst->done); | |
824 | } | |
825 | ||
826 | static void hfi_session_stop_done(struct venus_core *core, | |
827 | struct venus_inst *inst, void *packet) | |
828 | { | |
829 | struct hfi_msg_session_stop_done_pkt *pkt = packet; | |
830 | ||
831 | inst->error = pkt->error_type; | |
832 | complete(&inst->done); | |
833 | } | |
834 | ||
835 | static void hfi_session_rel_res_done(struct venus_core *core, | |
836 | struct venus_inst *inst, void *packet) | |
837 | { | |
838 | struct hfi_msg_session_release_resources_done_pkt *pkt = packet; | |
839 | ||
840 | inst->error = pkt->error_type; | |
841 | complete(&inst->done); | |
842 | } | |
843 | ||
844 | static void hfi_session_rel_buf_done(struct venus_core *core, | |
845 | struct venus_inst *inst, void *packet) | |
846 | { | |
847 | struct hfi_msg_session_release_buffers_done_pkt *pkt = packet; | |
848 | ||
849 | inst->error = pkt->error_type; | |
850 | complete(&inst->done); | |
851 | } | |
852 | ||
853 | static void hfi_session_end_done(struct venus_core *core, | |
854 | struct venus_inst *inst, void *packet) | |
855 | { | |
856 | struct hfi_msg_session_end_done_pkt *pkt = packet; | |
857 | ||
858 | inst->error = pkt->error_type; | |
859 | complete(&inst->done); | |
860 | } | |
861 | ||
862 | static void hfi_session_abort_done(struct venus_core *core, | |
863 | struct venus_inst *inst, void *packet) | |
864 | { | |
865 | struct hfi_msg_sys_session_abort_done_pkt *pkt = packet; | |
866 | ||
867 | inst->error = pkt->error_type; | |
868 | complete(&inst->done); | |
869 | } | |
870 | ||
871 | static void hfi_session_get_seq_hdr_done(struct venus_core *core, | |
872 | struct venus_inst *inst, void *packet) | |
873 | { | |
874 | struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet; | |
875 | ||
876 | inst->error = pkt->error_type; | |
877 | complete(&inst->done); | |
878 | } | |
879 | ||
880 | struct hfi_done_handler { | |
881 | u32 pkt; | |
882 | u32 pkt_sz; | |
883 | u32 pkt_sz2; | |
884 | void (*done)(struct venus_core *, struct venus_inst *, void *); | |
885 | bool is_sys_pkt; | |
886 | }; | |
887 | ||
888 | static const struct hfi_done_handler handlers[] = { | |
889 | {.pkt = HFI_MSG_EVENT_NOTIFY, | |
890 | .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt), | |
891 | .done = hfi_event_notify, | |
892 | }, | |
893 | {.pkt = HFI_MSG_SYS_INIT, | |
894 | .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt), | |
895 | .done = hfi_sys_init_done, | |
896 | .is_sys_pkt = true, | |
897 | }, | |
898 | {.pkt = HFI_MSG_SYS_PROPERTY_INFO, | |
899 | .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt), | |
900 | .done = hfi_sys_property_info, | |
901 | .is_sys_pkt = true, | |
902 | }, | |
903 | {.pkt = HFI_MSG_SYS_RELEASE_RESOURCE, | |
904 | .pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt), | |
905 | .done = hfi_sys_rel_resource_done, | |
906 | .is_sys_pkt = true, | |
907 | }, | |
908 | {.pkt = HFI_MSG_SYS_PING_ACK, | |
909 | .pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt), | |
910 | .done = hfi_sys_ping_done, | |
911 | .is_sys_pkt = true, | |
912 | }, | |
913 | {.pkt = HFI_MSG_SYS_IDLE, | |
914 | .pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt), | |
915 | .done = hfi_sys_idle_done, | |
916 | .is_sys_pkt = true, | |
917 | }, | |
918 | {.pkt = HFI_MSG_SYS_PC_PREP, | |
919 | .pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt), | |
920 | .done = hfi_sys_pc_prepare_done, | |
921 | .is_sys_pkt = true, | |
922 | }, | |
923 | {.pkt = HFI_MSG_SYS_SESSION_INIT, | |
924 | .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt), | |
925 | .done = hfi_session_init_done, | |
926 | }, | |
927 | {.pkt = HFI_MSG_SYS_SESSION_END, | |
928 | .pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt), | |
929 | .done = hfi_session_end_done, | |
930 | }, | |
931 | {.pkt = HFI_MSG_SESSION_LOAD_RESOURCES, | |
932 | .pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt), | |
933 | .done = hfi_session_load_res_done, | |
934 | }, | |
935 | {.pkt = HFI_MSG_SESSION_START, | |
936 | .pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt), | |
937 | .done = hfi_session_start_done, | |
938 | }, | |
939 | {.pkt = HFI_MSG_SESSION_STOP, | |
940 | .pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt), | |
941 | .done = hfi_session_stop_done, | |
942 | }, | |
943 | {.pkt = HFI_MSG_SYS_SESSION_ABORT, | |
944 | .pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt), | |
945 | .done = hfi_session_abort_done, | |
946 | }, | |
947 | {.pkt = HFI_MSG_SESSION_EMPTY_BUFFER, | |
948 | .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt), | |
949 | .done = hfi_session_etb_done, | |
950 | }, | |
951 | {.pkt = HFI_MSG_SESSION_FILL_BUFFER, | |
952 | .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), | |
953 | .pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt), | |
954 | .done = hfi_session_ftb_done, | |
955 | }, | |
956 | {.pkt = HFI_MSG_SESSION_FLUSH, | |
957 | .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt), | |
958 | .done = hfi_session_flush_done, | |
959 | }, | |
960 | {.pkt = HFI_MSG_SESSION_PROPERTY_INFO, | |
961 | .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt), | |
962 | .done = hfi_session_prop_info, | |
963 | }, | |
964 | {.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES, | |
965 | .pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt), | |
966 | .done = hfi_session_rel_res_done, | |
967 | }, | |
968 | {.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER, | |
969 | .pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt), | |
970 | .done = hfi_session_get_seq_hdr_done, | |
971 | }, | |
972 | {.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS, | |
973 | .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt), | |
974 | .done = hfi_session_rel_buf_done, | |
975 | }, | |
976 | }; | |
977 | ||
978 | void hfi_process_watchdog_timeout(struct venus_core *core) | |
979 | { | |
980 | event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL); | |
981 | } | |
982 | ||
983 | static struct venus_inst *to_instance(struct venus_core *core, u32 session_id) | |
984 | { | |
985 | struct venus_inst *inst; | |
986 | ||
987 | mutex_lock(&core->lock); | |
988 | list_for_each_entry(inst, &core->instances, list) | |
989 | if (hash32_ptr(inst) == session_id) { | |
990 | mutex_unlock(&core->lock); | |
991 | return inst; | |
992 | } | |
993 | mutex_unlock(&core->lock); | |
994 | ||
995 | return NULL; | |
996 | } | |
997 | ||
998 | u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr) | |
999 | { | |
1000 | const struct hfi_done_handler *handler; | |
1001 | struct device *dev = core->dev; | |
1002 | struct venus_inst *inst; | |
1003 | bool found = false; | |
1004 | unsigned int i; | |
1005 | ||
1006 | for (i = 0; i < ARRAY_SIZE(handlers); i++) { | |
1007 | handler = &handlers[i]; | |
1008 | if (handler->pkt != hdr->pkt_type) | |
1009 | continue; | |
1010 | found = true; | |
1011 | break; | |
1012 | } | |
1013 | ||
1014 | if (!found) | |
1015 | return hdr->pkt_type; | |
1016 | ||
1017 | if (hdr->size && hdr->size < handler->pkt_sz && | |
1018 | hdr->size < handler->pkt_sz2) { | |
1019 | dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n", | |
1020 | hdr->size, handler->pkt_sz, hdr->pkt_type); | |
1021 | ||
1022 | return hdr->pkt_type; | |
1023 | } | |
1024 | ||
1025 | if (handler->is_sys_pkt) { | |
1026 | inst = NULL; | |
1027 | } else { | |
1028 | struct hfi_session_pkt *pkt; | |
1029 | ||
1030 | pkt = (struct hfi_session_pkt *)hdr; | |
1031 | inst = to_instance(core, pkt->shdr.session_id); | |
1032 | ||
1033 | if (!inst) | |
1034 | dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n", | |
1035 | pkt->shdr.session_id, | |
1036 | handler ? handler->pkt : 0); | |
1037 | ||
1038 | /* | |
1039 | * Event of type HFI_EVENT_SYS_ERROR will not have any session | |
1040 | * associated with it | |
1041 | */ | |
1042 | if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) { | |
1043 | dev_err(dev, "got invalid session id:%x\n", | |
1044 | pkt->shdr.session_id); | |
1045 | goto invalid_session; | |
1046 | } | |
1047 | } | |
1048 | ||
1049 | handler->done(core, inst, hdr); | |
1050 | ||
1051 | invalid_session: | |
1052 | return hdr->pkt_type; | |
1053 | } |