Commit | Line | Data |
---|---|---|
97fb5e8d | 1 | // SPDX-License-Identifier: GPL-2.0-only |
09c2845e SV |
2 | /* |
3 | * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. | |
4 | * Copyright (C) 2017 Linaro Ltd. | |
09c2845e SV |
5 | */ |
6 | #include <linux/hash.h> | |
7 | #include <linux/list.h> | |
8 | #include <linux/slab.h> | |
d566e78d | 9 | #include <linux/soc/qcom/smem.h> |
09c2845e SV |
10 | #include <media/videobuf2-v4l2.h> |
11 | ||
12 | #include "core.h" | |
13 | #include "hfi.h" | |
14 | #include "hfi_helper.h" | |
15 | #include "hfi_msgs.h" | |
1a73374a | 16 | #include "hfi_parser.h" |
09c2845e | 17 | |
d566e78d DA |
18 | #define SMEM_IMG_VER_TBL 469 |
19 | #define VER_STR_SZ 128 | |
20 | #define SMEM_IMG_OFFSET_VENUS (14 * 128) | |
21 | ||
09c2845e SV |
22 | static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, |
23 | struct hfi_msg_event_notify_pkt *pkt) | |
24 | { | |
9eb2146e | 25 | enum hfi_version ver = core->res->hfi_version; |
09c2845e SV |
26 | struct hfi_event_data event = {0}; |
27 | int num_properties_changed; | |
28 | struct hfi_framesize *frame_sz; | |
29 | struct hfi_profile_level *profile_level; | |
9eb2146e SV |
30 | struct hfi_bit_depth *pixel_depth; |
31 | struct hfi_pic_struct *pic_struct; | |
32 | struct hfi_colour_space *colour_info; | |
33 | struct hfi_buffer_requirements *bufreq; | |
34 | struct hfi_extradata_input_crop *crop; | |
16545aa3 | 35 | struct hfi_dpb_counts *dpb_count; |
09c2845e SV |
36 | u8 *data_ptr; |
37 | u32 ptype; | |
38 | ||
39 | inst->error = HFI_ERR_NONE; | |
40 | ||
41 | switch (pkt->event_data1) { | |
42 | case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES: | |
43 | case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES: | |
44 | break; | |
45 | default: | |
46 | inst->error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
47 | goto done; | |
48 | } | |
49 | ||
50 | event.event_type = pkt->event_data1; | |
51 | ||
52 | num_properties_changed = pkt->event_data2; | |
53 | if (!num_properties_changed) { | |
54 | inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
55 | goto done; | |
56 | } | |
57 | ||
58 | data_ptr = (u8 *)&pkt->ext_event_data[0]; | |
59 | do { | |
60 | ptype = *((u32 *)data_ptr); | |
61 | switch (ptype) { | |
62 | case HFI_PROPERTY_PARAM_FRAME_SIZE: | |
63 | data_ptr += sizeof(u32); | |
64 | frame_sz = (struct hfi_framesize *)data_ptr; | |
65 | event.width = frame_sz->width; | |
66 | event.height = frame_sz->height; | |
ea8afbab | 67 | data_ptr += sizeof(*frame_sz); |
09c2845e SV |
68 | break; |
69 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: | |
70 | data_ptr += sizeof(u32); | |
71 | profile_level = (struct hfi_profile_level *)data_ptr; | |
72 | event.profile = profile_level->profile; | |
73 | event.level = profile_level->level; | |
ea8afbab | 74 | data_ptr += sizeof(*profile_level); |
09c2845e | 75 | break; |
9eb2146e SV |
76 | case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: |
77 | data_ptr += sizeof(u32); | |
78 | pixel_depth = (struct hfi_bit_depth *)data_ptr; | |
79 | event.bit_depth = pixel_depth->bit_depth; | |
80 | data_ptr += sizeof(*pixel_depth); | |
81 | break; | |
82 | case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: | |
83 | data_ptr += sizeof(u32); | |
84 | pic_struct = (struct hfi_pic_struct *)data_ptr; | |
85 | event.pic_struct = pic_struct->progressive_only; | |
86 | data_ptr += sizeof(*pic_struct); | |
87 | break; | |
88 | case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: | |
89 | data_ptr += sizeof(u32); | |
90 | colour_info = (struct hfi_colour_space *)data_ptr; | |
91 | event.colour_space = colour_info->colour_space; | |
92 | data_ptr += sizeof(*colour_info); | |
93 | break; | |
94 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: | |
95 | data_ptr += sizeof(u32); | |
96 | event.entropy_mode = *(u32 *)data_ptr; | |
97 | data_ptr += sizeof(u32); | |
98 | break; | |
99 | case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: | |
100 | data_ptr += sizeof(u32); | |
101 | bufreq = (struct hfi_buffer_requirements *)data_ptr; | |
bbfc89e6 | 102 | event.buf_count = hfi_bufreq_get_count_min(bufreq, ver); |
9eb2146e SV |
103 | data_ptr += sizeof(*bufreq); |
104 | break; | |
105 | case HFI_INDEX_EXTRADATA_INPUT_CROP: | |
106 | data_ptr += sizeof(u32); | |
107 | crop = (struct hfi_extradata_input_crop *)data_ptr; | |
108 | event.input_crop.left = crop->left; | |
109 | event.input_crop.top = crop->top; | |
110 | event.input_crop.width = crop->width; | |
111 | event.input_crop.height = crop->height; | |
112 | data_ptr += sizeof(*crop); | |
113 | break; | |
16545aa3 DA |
114 | case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: |
115 | data_ptr += sizeof(u32); | |
116 | dpb_count = (struct hfi_dpb_counts *)data_ptr; | |
117 | event.buf_count = dpb_count->fw_min_cnt; | |
118 | data_ptr += sizeof(*dpb_count); | |
119 | break; | |
09c2845e SV |
120 | default: |
121 | break; | |
122 | } | |
123 | num_properties_changed--; | |
124 | } while (num_properties_changed > 0); | |
125 | ||
126 | done: | |
127 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
128 | } | |
129 | ||
130 | static void event_release_buffer_ref(struct venus_core *core, | |
131 | struct venus_inst *inst, | |
132 | struct hfi_msg_event_notify_pkt *pkt) | |
133 | { | |
134 | struct hfi_event_data event = {0}; | |
135 | struct hfi_msg_event_release_buffer_ref_pkt *data; | |
136 | ||
137 | data = (struct hfi_msg_event_release_buffer_ref_pkt *) | |
138 | pkt->ext_event_data; | |
139 | ||
140 | event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE; | |
141 | event.packet_buffer = data->packet_buffer; | |
142 | event.extradata_buffer = data->extradata_buffer; | |
143 | event.tag = data->output_tag; | |
144 | ||
145 | inst->error = HFI_ERR_NONE; | |
146 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
147 | } | |
148 | ||
149 | static void event_sys_error(struct venus_core *core, u32 event, | |
150 | struct hfi_msg_event_notify_pkt *pkt) | |
151 | { | |
152 | if (pkt) | |
8c91dc08 | 153 | dev_dbg(core->dev, VDBGH |
09c2845e SV |
154 | "sys error (session id:%x, data1:%x, data2:%x)\n", |
155 | pkt->shdr.session_id, pkt->event_data1, | |
156 | pkt->event_data2); | |
157 | ||
158 | core->core_ops->event_notify(core, event); | |
159 | } | |
160 | ||
161 | static void | |
162 | event_session_error(struct venus_core *core, struct venus_inst *inst, | |
163 | struct hfi_msg_event_notify_pkt *pkt) | |
164 | { | |
165 | struct device *dev = core->dev; | |
166 | ||
8c91dc08 | 167 | dev_dbg(dev, VDBGH "session error: event id:%x, session id:%x\n", |
09c2845e SV |
168 | pkt->event_data1, pkt->shdr.session_id); |
169 | ||
170 | if (!inst) | |
171 | return; | |
172 | ||
173 | switch (pkt->event_data1) { | |
174 | /* non fatal session errors */ | |
175 | case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: | |
176 | case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE: | |
177 | case HFI_ERR_SESSION_UNSUPPORTED_SETTING: | |
178 | case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: | |
179 | inst->error = HFI_ERR_NONE; | |
180 | break; | |
181 | default: | |
182 | dev_err(dev, "session error: event id:%x (%x), session id:%x\n", | |
183 | pkt->event_data1, pkt->event_data2, | |
184 | pkt->shdr.session_id); | |
185 | ||
186 | inst->error = pkt->event_data1; | |
187 | inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); | |
188 | break; | |
189 | } | |
190 | } | |
191 | ||
192 | static void hfi_event_notify(struct venus_core *core, struct venus_inst *inst, | |
193 | void *packet) | |
194 | { | |
195 | struct hfi_msg_event_notify_pkt *pkt = packet; | |
196 | ||
197 | if (!packet) | |
198 | return; | |
199 | ||
200 | switch (pkt->event_id) { | |
201 | case HFI_EVENT_SYS_ERROR: | |
202 | event_sys_error(core, EVT_SYS_ERROR, pkt); | |
203 | break; | |
204 | case HFI_EVENT_SESSION_ERROR: | |
205 | event_session_error(core, inst, pkt); | |
206 | break; | |
207 | case HFI_EVENT_SESSION_SEQUENCE_CHANGED: | |
208 | event_seq_changed(core, inst, pkt); | |
209 | break; | |
210 | case HFI_EVENT_RELEASE_BUFFER_REFERENCE: | |
211 | event_release_buffer_ref(core, inst, pkt); | |
212 | break; | |
213 | case HFI_EVENT_SESSION_PROPERTY_CHANGED: | |
214 | break; | |
215 | default: | |
216 | break; | |
217 | } | |
218 | } | |
219 | ||
220 | static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst, | |
221 | void *packet) | |
222 | { | |
223 | struct hfi_msg_sys_init_done_pkt *pkt = packet; | |
1a73374a SV |
224 | int rem_bytes; |
225 | u32 error; | |
09c2845e SV |
226 | |
227 | error = pkt->error_type; | |
228 | if (error != HFI_ERR_NONE) | |
1a73374a | 229 | goto done; |
09c2845e | 230 | |
1a73374a | 231 | if (!pkt->num_properties) { |
09c2845e | 232 | error = HFI_ERR_SYS_INVALID_PARAMETER; |
1a73374a | 233 | goto done; |
09c2845e SV |
234 | } |
235 | ||
a80d6771 | 236 | rem_bytes = pkt->hdr.size - sizeof(*pkt); |
1a73374a | 237 | if (rem_bytes <= 0) { |
09c2845e SV |
238 | /* missing property data */ |
239 | error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES; | |
1a73374a | 240 | goto done; |
09c2845e SV |
241 | } |
242 | ||
1a73374a | 243 | error = hfi_parser(core, inst, pkt->data, rem_bytes); |
09c2845e | 244 | |
1a73374a | 245 | done: |
09c2845e SV |
246 | core->error = error; |
247 | complete(&core->done); | |
248 | } | |
249 | ||
250 | static void | |
ae8cdfc3 | 251 | sys_get_prop_image_version(struct venus_core *core, |
09c2845e SV |
252 | struct hfi_msg_sys_property_info_pkt *pkt) |
253 | { | |
ae8cdfc3 | 254 | struct device *dev = core->dev; |
d566e78d DA |
255 | u8 *smem_tbl_ptr; |
256 | u8 *img_ver; | |
09c2845e | 257 | int req_bytes; |
d566e78d | 258 | size_t smem_blk_sz; |
ae8cdfc3 | 259 | int ret; |
09c2845e SV |
260 | |
261 | req_bytes = pkt->hdr.size - sizeof(*pkt); | |
262 | ||
6f2f49ae | 263 | if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1) |
09c2845e SV |
264 | /* bad packet */ |
265 | return; | |
266 | ||
6f2f49ae | 267 | img_ver = pkt->data; |
ae8cdfc3 DA |
268 | if (!img_ver) |
269 | return; | |
270 | ||
271 | ret = sscanf(img_ver, "14:video-firmware.%u.%u-%u", | |
272 | &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev); | |
273 | if (ret) | |
274 | goto done; | |
275 | ||
276 | ret = sscanf(img_ver, "14:VIDEO.VPU.%u.%u-%u", | |
277 | &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev); | |
278 | if (ret) | |
279 | goto done; | |
280 | ||
281 | ret = sscanf(img_ver, "14:VIDEO.VE.%u.%u-%u", | |
282 | &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev); | |
283 | if (ret) | |
284 | goto done; | |
d566e78d | 285 | |
ae8cdfc3 DA |
286 | dev_err(dev, VDBGL "error reading F/W version\n"); |
287 | return; | |
288 | ||
289 | done: | |
290 | dev_dbg(dev, VDBGL "F/W version: %s, major %u, minor %u, revision %u\n", | |
291 | img_ver, core->venus_ver.major, core->venus_ver.minor, core->venus_ver.rev); | |
d566e78d DA |
292 | |
293 | smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, | |
294 | SMEM_IMG_VER_TBL, &smem_blk_sz); | |
331e06bb | 295 | if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) |
d566e78d DA |
296 | memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS, |
297 | img_ver, VER_STR_SZ); | |
09c2845e SV |
298 | } |
299 | ||
300 | static void hfi_sys_property_info(struct venus_core *core, | |
301 | struct venus_inst *inst, void *packet) | |
302 | { | |
303 | struct hfi_msg_sys_property_info_pkt *pkt = packet; | |
304 | struct device *dev = core->dev; | |
305 | ||
306 | if (!pkt->num_properties) { | |
8c91dc08 | 307 | dev_dbg(dev, VDBGL "no properties\n"); |
09c2845e SV |
308 | return; |
309 | } | |
310 | ||
6f2f49ae | 311 | switch (pkt->property) { |
09c2845e | 312 | case HFI_PROPERTY_SYS_IMAGE_VERSION: |
ae8cdfc3 | 313 | sys_get_prop_image_version(core, pkt); |
09c2845e SV |
314 | break; |
315 | default: | |
8c91dc08 | 316 | dev_dbg(dev, VDBGL "unknown property data\n"); |
09c2845e SV |
317 | break; |
318 | } | |
319 | } | |
320 | ||
321 | static void hfi_sys_rel_resource_done(struct venus_core *core, | |
322 | struct venus_inst *inst, | |
323 | void *packet) | |
324 | { | |
325 | struct hfi_msg_sys_release_resource_done_pkt *pkt = packet; | |
326 | ||
327 | core->error = pkt->error_type; | |
328 | complete(&core->done); | |
329 | } | |
330 | ||
331 | static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst, | |
332 | void *packet) | |
333 | { | |
334 | struct hfi_msg_sys_ping_ack_pkt *pkt = packet; | |
335 | ||
336 | core->error = HFI_ERR_NONE; | |
337 | ||
338 | if (pkt->client_data != 0xbeef) | |
339 | core->error = HFI_ERR_SYS_FATAL; | |
340 | ||
341 | complete(&core->done); | |
342 | } | |
343 | ||
344 | static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst, | |
345 | void *packet) | |
346 | { | |
8c91dc08 | 347 | dev_dbg(core->dev, VDBGL "sys idle\n"); |
09c2845e SV |
348 | } |
349 | ||
350 | static void hfi_sys_pc_prepare_done(struct venus_core *core, | |
351 | struct venus_inst *inst, void *packet) | |
352 | { | |
353 | struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet; | |
354 | ||
8c91dc08 SV |
355 | dev_dbg(core->dev, VDBGL "pc prepare done (error %x)\n", |
356 | pkt->error_type); | |
09c2845e SV |
357 | } |
358 | ||
09c2845e SV |
359 | static unsigned int |
360 | session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt, | |
361 | struct hfi_profile_level *profile_level) | |
362 | { | |
363 | struct hfi_profile_level *hfi; | |
364 | u32 req_bytes; | |
365 | ||
366 | req_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | |
367 | ||
368 | if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) | |
369 | /* bad packet */ | |
370 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
371 | ||
6f2f49ae | 372 | hfi = (struct hfi_profile_level *)&pkt->data[0]; |
09c2845e SV |
373 | profile_level->profile = hfi->profile; |
374 | profile_level->level = hfi->level; | |
375 | ||
376 | return HFI_ERR_NONE; | |
377 | } | |
378 | ||
379 | static unsigned int | |
380 | session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt, | |
381 | struct hfi_buffer_requirements *bufreq) | |
382 | { | |
383 | struct hfi_buffer_requirements *buf_req; | |
384 | u32 req_bytes; | |
385 | unsigned int idx = 0; | |
386 | ||
387 | req_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | |
388 | ||
6f2f49ae | 389 | if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0]) |
09c2845e SV |
390 | /* bad packet */ |
391 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
392 | ||
6f2f49ae | 393 | buf_req = (struct hfi_buffer_requirements *)&pkt->data[0]; |
09c2845e SV |
394 | if (!buf_req) |
395 | return HFI_ERR_SESSION_INVALID_PARAMETER; | |
396 | ||
397 | while (req_bytes) { | |
398 | memcpy(&bufreq[idx], buf_req, sizeof(*bufreq)); | |
399 | idx++; | |
400 | ||
b18e36df | 401 | if (idx >= HFI_BUFFER_TYPE_MAX) |
09c2845e SV |
402 | return HFI_ERR_SESSION_INVALID_PARAMETER; |
403 | ||
404 | req_bytes -= sizeof(struct hfi_buffer_requirements); | |
405 | buf_req++; | |
406 | } | |
407 | ||
408 | return HFI_ERR_NONE; | |
409 | } | |
410 | ||
411 | static void hfi_session_prop_info(struct venus_core *core, | |
412 | struct venus_inst *inst, void *packet) | |
413 | { | |
414 | struct hfi_msg_session_property_info_pkt *pkt = packet; | |
415 | struct device *dev = core->dev; | |
416 | union hfi_get_property *hprop = &inst->hprop; | |
417 | unsigned int error = HFI_ERR_NONE; | |
418 | ||
419 | if (!pkt->num_properties) { | |
420 | error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
421 | dev_err(dev, "%s: no properties\n", __func__); | |
422 | goto done; | |
423 | } | |
424 | ||
6f2f49ae | 425 | switch (pkt->property) { |
09c2845e SV |
426 | case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: |
427 | memset(hprop->bufreq, 0, sizeof(hprop->bufreq)); | |
428 | error = session_get_prop_buf_req(pkt, hprop->bufreq); | |
429 | break; | |
430 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: | |
431 | memset(&hprop->profile_level, 0, sizeof(hprop->profile_level)); | |
432 | error = session_get_prop_profile_level(pkt, | |
433 | &hprop->profile_level); | |
434 | break; | |
435 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: | |
436 | break; | |
437 | default: | |
6f2f49ae | 438 | dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property); |
09c2845e SV |
439 | return; |
440 | } | |
441 | ||
442 | done: | |
443 | inst->error = error; | |
444 | complete(&inst->done); | |
445 | } | |
446 | ||
09c2845e SV |
447 | static void hfi_session_init_done(struct venus_core *core, |
448 | struct venus_inst *inst, void *packet) | |
449 | { | |
450 | struct hfi_msg_session_init_done_pkt *pkt = packet; | |
1a73374a SV |
451 | int rem_bytes; |
452 | u32 error; | |
09c2845e SV |
453 | |
454 | error = pkt->error_type; | |
455 | if (error != HFI_ERR_NONE) | |
456 | goto done; | |
457 | ||
1a73374a | 458 | if (!IS_V1(core)) |
09c2845e SV |
459 | goto done; |
460 | ||
a80d6771 | 461 | rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt); |
1a73374a SV |
462 | if (rem_bytes <= 0) { |
463 | error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
464 | goto done; | |
465 | } | |
09c2845e | 466 | |
1a73374a | 467 | error = hfi_parser(core, inst, pkt->data, rem_bytes); |
09c2845e SV |
468 | done: |
469 | inst->error = error; | |
470 | complete(&inst->done); | |
471 | } | |
472 | ||
473 | static void hfi_session_load_res_done(struct venus_core *core, | |
474 | struct venus_inst *inst, void *packet) | |
475 | { | |
476 | struct hfi_msg_session_load_resources_done_pkt *pkt = packet; | |
477 | ||
478 | inst->error = pkt->error_type; | |
479 | complete(&inst->done); | |
480 | } | |
481 | ||
482 | static void hfi_session_flush_done(struct venus_core *core, | |
483 | struct venus_inst *inst, void *packet) | |
484 | { | |
485 | struct hfi_msg_session_flush_done_pkt *pkt = packet; | |
486 | ||
487 | inst->error = pkt->error_type; | |
488 | complete(&inst->done); | |
85872f86 SV |
489 | if (inst->ops->flush_done) |
490 | inst->ops->flush_done(inst); | |
09c2845e SV |
491 | } |
492 | ||
493 | static void hfi_session_etb_done(struct venus_core *core, | |
494 | struct venus_inst *inst, void *packet) | |
495 | { | |
496 | struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet; | |
497 | ||
498 | inst->error = pkt->error_type; | |
499 | inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag, | |
500 | pkt->filled_len, pkt->offset, 0, 0, 0); | |
501 | } | |
502 | ||
503 | static void hfi_session_ftb_done(struct venus_core *core, | |
504 | struct venus_inst *inst, void *packet) | |
505 | { | |
506 | u32 session_type = inst->session_type; | |
507 | u64 timestamp_us = 0; | |
508 | u32 timestamp_hi = 0, timestamp_lo = 0; | |
509 | unsigned int error; | |
510 | u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0; | |
511 | u32 pic_type = 0, buffer_type = 0, output_tag = -1; | |
512 | ||
513 | if (session_type == VIDC_SESSION_TYPE_ENC) { | |
514 | struct hfi_msg_session_fbd_compressed_pkt *pkt = packet; | |
515 | ||
516 | timestamp_hi = pkt->time_stamp_hi; | |
517 | timestamp_lo = pkt->time_stamp_lo; | |
518 | hfi_flags = pkt->flags; | |
519 | offset = pkt->offset; | |
520 | filled_len = pkt->filled_len; | |
521 | pic_type = pkt->picture_type; | |
522 | output_tag = pkt->output_tag; | |
523 | buffer_type = HFI_BUFFER_OUTPUT; | |
524 | ||
525 | error = pkt->error_type; | |
526 | } else if (session_type == VIDC_SESSION_TYPE_DEC) { | |
527 | struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt = | |
528 | packet; | |
529 | ||
530 | timestamp_hi = pkt->time_stamp_hi; | |
531 | timestamp_lo = pkt->time_stamp_lo; | |
532 | hfi_flags = pkt->flags; | |
533 | offset = pkt->offset; | |
534 | filled_len = pkt->filled_len; | |
535 | pic_type = pkt->picture_type; | |
536 | output_tag = pkt->output_tag; | |
537 | ||
538 | if (pkt->stream_id == 0) | |
539 | buffer_type = HFI_BUFFER_OUTPUT; | |
540 | else if (pkt->stream_id == 1) | |
541 | buffer_type = HFI_BUFFER_OUTPUT2; | |
542 | ||
543 | error = pkt->error_type; | |
544 | } else { | |
545 | error = HFI_ERR_SESSION_INVALID_PARAMETER; | |
546 | } | |
547 | ||
5f43f90a SV |
548 | if (buffer_type != HFI_BUFFER_OUTPUT && |
549 | buffer_type != HFI_BUFFER_OUTPUT2) | |
09c2845e SV |
550 | goto done; |
551 | ||
552 | if (hfi_flags & HFI_BUFFERFLAG_EOS) | |
553 | flags |= V4L2_BUF_FLAG_LAST; | |
554 | ||
555 | switch (pic_type) { | |
556 | case HFI_PICTURE_IDR: | |
557 | case HFI_PICTURE_I: | |
558 | flags |= V4L2_BUF_FLAG_KEYFRAME; | |
559 | break; | |
560 | case HFI_PICTURE_P: | |
561 | flags |= V4L2_BUF_FLAG_PFRAME; | |
562 | break; | |
563 | case HFI_PICTURE_B: | |
564 | flags |= V4L2_BUF_FLAG_BFRAME; | |
565 | break; | |
566 | case HFI_FRAME_NOTCODED: | |
567 | case HFI_UNUSED_PICT: | |
568 | case HFI_FRAME_YUV: | |
569 | default: | |
570 | break; | |
571 | } | |
572 | ||
573 | if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) { | |
574 | timestamp_us = timestamp_hi; | |
575 | timestamp_us = (timestamp_us << 32) | timestamp_lo; | |
576 | } | |
577 | ||
578 | done: | |
579 | inst->error = error; | |
580 | inst->ops->buf_done(inst, buffer_type, output_tag, filled_len, | |
581 | offset, flags, hfi_flags, timestamp_us); | |
582 | } | |
583 | ||
584 | static void hfi_session_start_done(struct venus_core *core, | |
585 | struct venus_inst *inst, void *packet) | |
586 | { | |
587 | struct hfi_msg_session_start_done_pkt *pkt = packet; | |
588 | ||
589 | inst->error = pkt->error_type; | |
590 | complete(&inst->done); | |
591 | } | |
592 | ||
593 | static void hfi_session_stop_done(struct venus_core *core, | |
594 | struct venus_inst *inst, void *packet) | |
595 | { | |
596 | struct hfi_msg_session_stop_done_pkt *pkt = packet; | |
597 | ||
598 | inst->error = pkt->error_type; | |
599 | complete(&inst->done); | |
600 | } | |
601 | ||
602 | static void hfi_session_rel_res_done(struct venus_core *core, | |
603 | struct venus_inst *inst, void *packet) | |
604 | { | |
605 | struct hfi_msg_session_release_resources_done_pkt *pkt = packet; | |
606 | ||
607 | inst->error = pkt->error_type; | |
608 | complete(&inst->done); | |
609 | } | |
610 | ||
611 | static void hfi_session_rel_buf_done(struct venus_core *core, | |
612 | struct venus_inst *inst, void *packet) | |
613 | { | |
614 | struct hfi_msg_session_release_buffers_done_pkt *pkt = packet; | |
615 | ||
616 | inst->error = pkt->error_type; | |
617 | complete(&inst->done); | |
618 | } | |
619 | ||
620 | static void hfi_session_end_done(struct venus_core *core, | |
621 | struct venus_inst *inst, void *packet) | |
622 | { | |
623 | struct hfi_msg_session_end_done_pkt *pkt = packet; | |
624 | ||
625 | inst->error = pkt->error_type; | |
626 | complete(&inst->done); | |
627 | } | |
628 | ||
629 | static void hfi_session_abort_done(struct venus_core *core, | |
630 | struct venus_inst *inst, void *packet) | |
631 | { | |
632 | struct hfi_msg_sys_session_abort_done_pkt *pkt = packet; | |
633 | ||
634 | inst->error = pkt->error_type; | |
635 | complete(&inst->done); | |
636 | } | |
637 | ||
638 | static void hfi_session_get_seq_hdr_done(struct venus_core *core, | |
639 | struct venus_inst *inst, void *packet) | |
640 | { | |
641 | struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet; | |
642 | ||
643 | inst->error = pkt->error_type; | |
644 | complete(&inst->done); | |
645 | } | |
646 | ||
647 | struct hfi_done_handler { | |
648 | u32 pkt; | |
649 | u32 pkt_sz; | |
650 | u32 pkt_sz2; | |
651 | void (*done)(struct venus_core *, struct venus_inst *, void *); | |
652 | bool is_sys_pkt; | |
653 | }; | |
654 | ||
655 | static const struct hfi_done_handler handlers[] = { | |
656 | {.pkt = HFI_MSG_EVENT_NOTIFY, | |
657 | .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt), | |
658 | .done = hfi_event_notify, | |
659 | }, | |
660 | {.pkt = HFI_MSG_SYS_INIT, | |
661 | .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt), | |
662 | .done = hfi_sys_init_done, | |
663 | .is_sys_pkt = true, | |
664 | }, | |
665 | {.pkt = HFI_MSG_SYS_PROPERTY_INFO, | |
666 | .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt), | |
667 | .done = hfi_sys_property_info, | |
668 | .is_sys_pkt = true, | |
669 | }, | |
670 | {.pkt = HFI_MSG_SYS_RELEASE_RESOURCE, | |
671 | .pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt), | |
672 | .done = hfi_sys_rel_resource_done, | |
673 | .is_sys_pkt = true, | |
674 | }, | |
675 | {.pkt = HFI_MSG_SYS_PING_ACK, | |
676 | .pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt), | |
677 | .done = hfi_sys_ping_done, | |
678 | .is_sys_pkt = true, | |
679 | }, | |
680 | {.pkt = HFI_MSG_SYS_IDLE, | |
681 | .pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt), | |
682 | .done = hfi_sys_idle_done, | |
683 | .is_sys_pkt = true, | |
684 | }, | |
685 | {.pkt = HFI_MSG_SYS_PC_PREP, | |
686 | .pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt), | |
687 | .done = hfi_sys_pc_prepare_done, | |
688 | .is_sys_pkt = true, | |
689 | }, | |
690 | {.pkt = HFI_MSG_SYS_SESSION_INIT, | |
691 | .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt), | |
692 | .done = hfi_session_init_done, | |
693 | }, | |
694 | {.pkt = HFI_MSG_SYS_SESSION_END, | |
695 | .pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt), | |
696 | .done = hfi_session_end_done, | |
697 | }, | |
698 | {.pkt = HFI_MSG_SESSION_LOAD_RESOURCES, | |
699 | .pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt), | |
700 | .done = hfi_session_load_res_done, | |
701 | }, | |
702 | {.pkt = HFI_MSG_SESSION_START, | |
703 | .pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt), | |
704 | .done = hfi_session_start_done, | |
705 | }, | |
706 | {.pkt = HFI_MSG_SESSION_STOP, | |
707 | .pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt), | |
708 | .done = hfi_session_stop_done, | |
709 | }, | |
710 | {.pkt = HFI_MSG_SYS_SESSION_ABORT, | |
711 | .pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt), | |
712 | .done = hfi_session_abort_done, | |
713 | }, | |
714 | {.pkt = HFI_MSG_SESSION_EMPTY_BUFFER, | |
715 | .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt), | |
716 | .done = hfi_session_etb_done, | |
717 | }, | |
718 | {.pkt = HFI_MSG_SESSION_FILL_BUFFER, | |
719 | .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), | |
720 | .pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt), | |
721 | .done = hfi_session_ftb_done, | |
722 | }, | |
723 | {.pkt = HFI_MSG_SESSION_FLUSH, | |
724 | .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt), | |
725 | .done = hfi_session_flush_done, | |
726 | }, | |
727 | {.pkt = HFI_MSG_SESSION_PROPERTY_INFO, | |
728 | .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt), | |
729 | .done = hfi_session_prop_info, | |
730 | }, | |
731 | {.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES, | |
732 | .pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt), | |
733 | .done = hfi_session_rel_res_done, | |
734 | }, | |
735 | {.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER, | |
736 | .pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt), | |
737 | .done = hfi_session_get_seq_hdr_done, | |
738 | }, | |
739 | {.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS, | |
740 | .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt), | |
741 | .done = hfi_session_rel_buf_done, | |
742 | }, | |
743 | }; | |
744 | ||
745 | void hfi_process_watchdog_timeout(struct venus_core *core) | |
746 | { | |
747 | event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL); | |
748 | } | |
749 | ||
750 | static struct venus_inst *to_instance(struct venus_core *core, u32 session_id) | |
751 | { | |
752 | struct venus_inst *inst; | |
753 | ||
754 | mutex_lock(&core->lock); | |
755 | list_for_each_entry(inst, &core->instances, list) | |
756 | if (hash32_ptr(inst) == session_id) { | |
757 | mutex_unlock(&core->lock); | |
758 | return inst; | |
759 | } | |
760 | mutex_unlock(&core->lock); | |
761 | ||
762 | return NULL; | |
763 | } | |
764 | ||
765 | u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr) | |
766 | { | |
767 | const struct hfi_done_handler *handler; | |
768 | struct device *dev = core->dev; | |
769 | struct venus_inst *inst; | |
770 | bool found = false; | |
771 | unsigned int i; | |
772 | ||
773 | for (i = 0; i < ARRAY_SIZE(handlers); i++) { | |
774 | handler = &handlers[i]; | |
775 | if (handler->pkt != hdr->pkt_type) | |
776 | continue; | |
777 | found = true; | |
778 | break; | |
779 | } | |
780 | ||
781 | if (!found) | |
782 | return hdr->pkt_type; | |
783 | ||
784 | if (hdr->size && hdr->size < handler->pkt_sz && | |
785 | hdr->size < handler->pkt_sz2) { | |
786 | dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n", | |
787 | hdr->size, handler->pkt_sz, hdr->pkt_type); | |
788 | ||
789 | return hdr->pkt_type; | |
790 | } | |
791 | ||
792 | if (handler->is_sys_pkt) { | |
793 | inst = NULL; | |
794 | } else { | |
795 | struct hfi_session_pkt *pkt; | |
796 | ||
797 | pkt = (struct hfi_session_pkt *)hdr; | |
798 | inst = to_instance(core, pkt->shdr.session_id); | |
799 | ||
800 | if (!inst) | |
801 | dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n", | |
802 | pkt->shdr.session_id, | |
803 | handler ? handler->pkt : 0); | |
804 | ||
805 | /* | |
806 | * Event of type HFI_EVENT_SYS_ERROR will not have any session | |
807 | * associated with it | |
808 | */ | |
809 | if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) { | |
810 | dev_err(dev, "got invalid session id:%x\n", | |
811 | pkt->shdr.session_id); | |
812 | goto invalid_session; | |
813 | } | |
814 | } | |
815 | ||
816 | handler->done(core, inst, hdr); | |
817 | ||
818 | invalid_session: | |
819 | return hdr->pkt_type; | |
820 | } |