1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2017 Linaro Ltd.
5 */
6 #include <linux/slab.h>
7 #include <linux/mutex.h>
8 #include <linux/list.h>
9 #include <linux/completion.h>
10 #include <linux/platform_device.h>
11 #include <linux/videodev2.h>
12
13 #include "core.h"
14 #include "hfi.h"
15 #include "hfi_cmds.h"
16 #include "hfi_venus.h"
17
18 #define TIMEOUT msecs_to_jiffies(1000)
19
to_codec_type(u32 pixfmt)20 static u32 to_codec_type(u32 pixfmt)
21 {
22 switch (pixfmt) {
23 case V4L2_PIX_FMT_H264:
24 case V4L2_PIX_FMT_H264_NO_SC:
25 return HFI_VIDEO_CODEC_H264;
26 case V4L2_PIX_FMT_H263:
27 return HFI_VIDEO_CODEC_H263;
28 case V4L2_PIX_FMT_MPEG1:
29 return HFI_VIDEO_CODEC_MPEG1;
30 case V4L2_PIX_FMT_MPEG2:
31 return HFI_VIDEO_CODEC_MPEG2;
32 case V4L2_PIX_FMT_MPEG4:
33 return HFI_VIDEO_CODEC_MPEG4;
34 case V4L2_PIX_FMT_VC1_ANNEX_G:
35 case V4L2_PIX_FMT_VC1_ANNEX_L:
36 return HFI_VIDEO_CODEC_VC1;
37 case V4L2_PIX_FMT_VP8:
38 return HFI_VIDEO_CODEC_VP8;
39 case V4L2_PIX_FMT_VP9:
40 return HFI_VIDEO_CODEC_VP9;
41 case V4L2_PIX_FMT_XVID:
42 return HFI_VIDEO_CODEC_DIVX;
43 case V4L2_PIX_FMT_HEVC:
44 return HFI_VIDEO_CODEC_HEVC;
45 default:
46 return 0;
47 }
48 }
49
hfi_core_init(struct venus_core * core)50 int hfi_core_init(struct venus_core *core)
51 {
52 int ret = 0;
53
54 mutex_lock(&core->lock);
55
56 if (core->state >= CORE_INIT)
57 goto unlock;
58
59 reinit_completion(&core->done);
60
61 ret = core->ops->core_init(core);
62 if (ret)
63 goto unlock;
64
65 ret = wait_for_completion_timeout(&core->done, TIMEOUT);
66 if (!ret) {
67 ret = -ETIMEDOUT;
68 goto unlock;
69 }
70
71 ret = 0;
72
73 if (core->error != HFI_ERR_NONE) {
74 ret = -EIO;
75 goto unlock;
76 }
77
78 core->state = CORE_INIT;
79 unlock:
80 mutex_unlock(&core->lock);
81 return ret;
82 }
83
hfi_core_deinit(struct venus_core * core,bool blocking)84 int hfi_core_deinit(struct venus_core *core, bool blocking)
85 {
86 int ret = 0, empty;
87
88 mutex_lock(&core->lock);
89
90 if (core->state == CORE_UNINIT)
91 goto unlock;
92
93 empty = list_empty(&core->instances);
94
95 if (!empty && !blocking) {
96 ret = -EBUSY;
97 goto unlock;
98 }
99
100 if (!empty) {
101 mutex_unlock(&core->lock);
102 wait_var_event(&core->insts_count,
103 !atomic_read(&core->insts_count));
104 mutex_lock(&core->lock);
105 }
106
107 if (!core->ops)
108 goto unlock;
109
110 ret = core->ops->core_deinit(core);
111
112 if (!ret)
113 core->state = CORE_UNINIT;
114
115 unlock:
116 mutex_unlock(&core->lock);
117 return ret;
118 }
119
hfi_core_suspend(struct venus_core * core)120 int hfi_core_suspend(struct venus_core *core)
121 {
122 if (core->state != CORE_INIT)
123 return 0;
124
125 return core->ops->suspend(core);
126 }
127
hfi_core_resume(struct venus_core * core,bool force)128 int hfi_core_resume(struct venus_core *core, bool force)
129 {
130 if (!force && core->state != CORE_INIT)
131 return 0;
132
133 return core->ops->resume(core);
134 }
135
hfi_core_trigger_ssr(struct venus_core * core,u32 type)136 int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
137 {
138 return core->ops->core_trigger_ssr(core, type);
139 }
140
hfi_core_ping(struct venus_core * core)141 int hfi_core_ping(struct venus_core *core)
142 {
143 int ret;
144
145 mutex_lock(&core->lock);
146
147 ret = core->ops->core_ping(core, 0xbeef);
148 if (ret)
149 goto unlock;
150
151 ret = wait_for_completion_timeout(&core->done, TIMEOUT);
152 if (!ret) {
153 ret = -ETIMEDOUT;
154 goto unlock;
155 }
156 ret = 0;
157 if (core->error != HFI_ERR_NONE)
158 ret = -ENODEV;
159 unlock:
160 mutex_unlock(&core->lock);
161 return ret;
162 }
163
wait_session_msg(struct venus_inst * inst)164 static int wait_session_msg(struct venus_inst *inst)
165 {
166 int ret;
167
168 ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
169 if (!ret)
170 return -ETIMEDOUT;
171
172 if (inst->error != HFI_ERR_NONE)
173 return -EIO;
174
175 return 0;
176 }
177
hfi_session_create(struct venus_inst * inst,const struct hfi_inst_ops * ops)178 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
179 {
180 struct venus_core *core = inst->core;
181 bool max;
182 int ret;
183
184 if (!ops)
185 return -EINVAL;
186
187 inst->state = INST_UNINIT;
188 init_completion(&inst->done);
189 inst->ops = ops;
190
191 mutex_lock(&core->lock);
192
193 if (test_bit(0, &inst->core->sys_error)) {
194 ret = -EIO;
195 goto unlock;
196 }
197
198 max = atomic_add_unless(&core->insts_count, 1,
199 core->max_sessions_supported);
200 if (!max) {
201 ret = -EAGAIN;
202 } else {
203 list_add_tail(&inst->list, &core->instances);
204 ret = 0;
205 }
206
207 unlock:
208 mutex_unlock(&core->lock);
209
210 return ret;
211 }
212 EXPORT_SYMBOL_GPL(hfi_session_create);
213
hfi_session_init(struct venus_inst * inst,u32 pixfmt)214 int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
215 {
216 struct venus_core *core = inst->core;
217 const struct hfi_ops *ops = core->ops;
218 int ret;
219
220 /*
221 * If core shutdown is in progress or if we are in system
222 * recovery, return an error as during system error recovery
223 * session_init() can't pass successfully
224 */
225 mutex_lock(&core->lock);
226 if (!core->ops || test_bit(0, &inst->core->sys_error)) {
227 mutex_unlock(&core->lock);
228 return -EIO;
229 }
230 mutex_unlock(&core->lock);
231
232 if (inst->state != INST_UNINIT)
233 return -EALREADY;
234
235 inst->hfi_codec = to_codec_type(pixfmt);
236 reinit_completion(&inst->done);
237
238 ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
239 if (ret)
240 return ret;
241
242 ret = wait_session_msg(inst);
243 if (ret)
244 return ret;
245
246 inst->state = INST_INIT;
247
248 return 0;
249 }
250 EXPORT_SYMBOL_GPL(hfi_session_init);
251
hfi_session_destroy(struct venus_inst * inst)252 void hfi_session_destroy(struct venus_inst *inst)
253 {
254 struct venus_core *core = inst->core;
255
256 mutex_lock(&core->lock);
257 list_del_init(&inst->list);
258 if (atomic_dec_and_test(&core->insts_count))
259 wake_up_var(&core->insts_count);
260 mutex_unlock(&core->lock);
261 }
262 EXPORT_SYMBOL_GPL(hfi_session_destroy);
263
hfi_session_deinit(struct venus_inst * inst)264 int hfi_session_deinit(struct venus_inst *inst)
265 {
266 const struct hfi_ops *ops = inst->core->ops;
267 int ret;
268
269 if (inst->state == INST_UNINIT)
270 return 0;
271
272 if (inst->state < INST_INIT)
273 return -EINVAL;
274
275 if (test_bit(0, &inst->core->sys_error))
276 goto done;
277
278 reinit_completion(&inst->done);
279
280 ret = ops->session_end(inst);
281 if (ret)
282 return ret;
283
284 ret = wait_session_msg(inst);
285 if (ret)
286 return ret;
287
288 done:
289 inst->state = INST_UNINIT;
290
291 return 0;
292 }
293 EXPORT_SYMBOL_GPL(hfi_session_deinit);
294
hfi_session_start(struct venus_inst * inst)295 int hfi_session_start(struct venus_inst *inst)
296 {
297 const struct hfi_ops *ops = inst->core->ops;
298 int ret;
299
300 if (test_bit(0, &inst->core->sys_error))
301 return -EIO;
302
303 if (inst->state != INST_LOAD_RESOURCES)
304 return -EINVAL;
305
306 reinit_completion(&inst->done);
307
308 ret = ops->session_start(inst);
309 if (ret)
310 return ret;
311
312 ret = wait_session_msg(inst);
313 if (ret)
314 return ret;
315
316 inst->state = INST_START;
317
318 return 0;
319 }
320 EXPORT_SYMBOL_GPL(hfi_session_start);
321
hfi_session_stop(struct venus_inst * inst)322 int hfi_session_stop(struct venus_inst *inst)
323 {
324 const struct hfi_ops *ops = inst->core->ops;
325 int ret;
326
327 if (test_bit(0, &inst->core->sys_error))
328 return -EIO;
329
330 if (inst->state != INST_START)
331 return -EINVAL;
332
333 reinit_completion(&inst->done);
334
335 ret = ops->session_stop(inst);
336 if (ret)
337 return ret;
338
339 ret = wait_session_msg(inst);
340 if (ret)
341 return ret;
342
343 inst->state = INST_STOP;
344
345 return 0;
346 }
347 EXPORT_SYMBOL_GPL(hfi_session_stop);
348
hfi_session_continue(struct venus_inst * inst)349 int hfi_session_continue(struct venus_inst *inst)
350 {
351 struct venus_core *core = inst->core;
352
353 if (test_bit(0, &inst->core->sys_error))
354 return -EIO;
355
356 if (core->res->hfi_version == HFI_VERSION_1XX)
357 return 0;
358
359 return core->ops->session_continue(inst);
360 }
361 EXPORT_SYMBOL_GPL(hfi_session_continue);
362
hfi_session_abort(struct venus_inst * inst)363 int hfi_session_abort(struct venus_inst *inst)
364 {
365 const struct hfi_ops *ops = inst->core->ops;
366 int ret;
367
368 if (test_bit(0, &inst->core->sys_error))
369 return -EIO;
370
371 reinit_completion(&inst->done);
372
373 ret = ops->session_abort(inst);
374 if (ret)
375 return ret;
376
377 ret = wait_session_msg(inst);
378 if (ret)
379 return ret;
380
381 return 0;
382 }
383 EXPORT_SYMBOL_GPL(hfi_session_abort);
384
hfi_session_load_res(struct venus_inst * inst)385 int hfi_session_load_res(struct venus_inst *inst)
386 {
387 const struct hfi_ops *ops = inst->core->ops;
388 int ret;
389
390 if (test_bit(0, &inst->core->sys_error))
391 return -EIO;
392
393 if (inst->state != INST_INIT)
394 return -EINVAL;
395
396 reinit_completion(&inst->done);
397
398 ret = ops->session_load_res(inst);
399 if (ret)
400 return ret;
401
402 ret = wait_session_msg(inst);
403 if (ret)
404 return ret;
405
406 inst->state = INST_LOAD_RESOURCES;
407
408 return 0;
409 }
410
hfi_session_unload_res(struct venus_inst * inst)411 int hfi_session_unload_res(struct venus_inst *inst)
412 {
413 const struct hfi_ops *ops = inst->core->ops;
414 int ret;
415
416 if (test_bit(0, &inst->core->sys_error))
417 return -EIO;
418
419 if (inst->state != INST_STOP)
420 return -EINVAL;
421
422 reinit_completion(&inst->done);
423
424 ret = ops->session_release_res(inst);
425 if (ret)
426 return ret;
427
428 ret = wait_session_msg(inst);
429 if (ret)
430 return ret;
431
432 inst->state = INST_RELEASE_RESOURCES;
433
434 return 0;
435 }
436 EXPORT_SYMBOL_GPL(hfi_session_unload_res);
437
hfi_session_flush(struct venus_inst * inst,u32 type,bool block)438 int hfi_session_flush(struct venus_inst *inst, u32 type, bool block)
439 {
440 const struct hfi_ops *ops = inst->core->ops;
441 int ret;
442
443 if (test_bit(0, &inst->core->sys_error))
444 return -EIO;
445
446 reinit_completion(&inst->done);
447
448 ret = ops->session_flush(inst, type);
449 if (ret)
450 return ret;
451
452 if (block) {
453 ret = wait_session_msg(inst);
454 if (ret)
455 return ret;
456 }
457
458 return 0;
459 }
460 EXPORT_SYMBOL_GPL(hfi_session_flush);
461
hfi_session_set_buffers(struct venus_inst * inst,struct hfi_buffer_desc * bd)462 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
463 {
464 const struct hfi_ops *ops = inst->core->ops;
465
466 if (test_bit(0, &inst->core->sys_error))
467 return -EIO;
468
469 return ops->session_set_buffers(inst, bd);
470 }
471
hfi_session_unset_buffers(struct venus_inst * inst,struct hfi_buffer_desc * bd)472 int hfi_session_unset_buffers(struct venus_inst *inst,
473 struct hfi_buffer_desc *bd)
474 {
475 const struct hfi_ops *ops = inst->core->ops;
476 int ret;
477
478 if (test_bit(0, &inst->core->sys_error))
479 return -EIO;
480
481 reinit_completion(&inst->done);
482
483 ret = ops->session_unset_buffers(inst, bd);
484 if (ret)
485 return ret;
486
487 if (!bd->response_required)
488 return 0;
489
490 ret = wait_session_msg(inst);
491 if (ret)
492 return ret;
493
494 return 0;
495 }
496
hfi_session_get_property(struct venus_inst * inst,u32 ptype,union hfi_get_property * hprop)497 int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
498 union hfi_get_property *hprop)
499 {
500 const struct hfi_ops *ops = inst->core->ops;
501 int ret;
502
503 if (test_bit(0, &inst->core->sys_error))
504 return -EIO;
505
506 if (inst->state < INST_INIT || inst->state >= INST_STOP)
507 return -EINVAL;
508
509 reinit_completion(&inst->done);
510
511 ret = ops->session_get_property(inst, ptype);
512 if (ret)
513 return ret;
514
515 ret = wait_session_msg(inst);
516 if (ret)
517 return ret;
518
519 *hprop = inst->hprop;
520
521 return 0;
522 }
523 EXPORT_SYMBOL_GPL(hfi_session_get_property);
524
hfi_session_set_property(struct venus_inst * inst,u32 ptype,void * pdata)525 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
526 {
527 const struct hfi_ops *ops = inst->core->ops;
528
529 if (test_bit(0, &inst->core->sys_error))
530 return -EIO;
531
532 if (inst->state < INST_INIT || inst->state >= INST_STOP)
533 return -EINVAL;
534
535 return ops->session_set_property(inst, ptype, pdata);
536 }
537 EXPORT_SYMBOL_GPL(hfi_session_set_property);
538
hfi_session_process_buf(struct venus_inst * inst,struct hfi_frame_data * fd)539 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
540 {
541 const struct hfi_ops *ops = inst->core->ops;
542
543 if (test_bit(0, &inst->core->sys_error))
544 return -EIO;
545
546 if (fd->buffer_type == HFI_BUFFER_INPUT)
547 return ops->session_etb(inst, fd);
548 else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
549 fd->buffer_type == HFI_BUFFER_OUTPUT2)
550 return ops->session_ftb(inst, fd);
551
552 return -EINVAL;
553 }
554 EXPORT_SYMBOL_GPL(hfi_session_process_buf);
555
hfi_isr_thread(int irq,void * dev_id)556 irqreturn_t hfi_isr_thread(int irq, void *dev_id)
557 {
558 struct venus_core *core = dev_id;
559
560 return core->ops->isr_thread(core);
561 }
562
hfi_isr(int irq,void * dev)563 irqreturn_t hfi_isr(int irq, void *dev)
564 {
565 struct venus_core *core = dev;
566
567 return core->ops->isr(core);
568 }
569
hfi_create(struct venus_core * core,const struct hfi_core_ops * ops)570 int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
571 {
572 if (!ops)
573 return -EINVAL;
574
575 atomic_set(&core->insts_count, 0);
576 core->core_ops = ops;
577 core->state = CORE_UNINIT;
578 init_completion(&core->done);
579 pkt_set_version(core->res->hfi_version);
580
581 return venus_hfi_create(core);
582 }
583
hfi_destroy(struct venus_core * core)584 void hfi_destroy(struct venus_core *core)
585 {
586 venus_hfi_destroy(core);
587 }
588
hfi_reinit(struct venus_core * core)589 void hfi_reinit(struct venus_core *core)
590 {
591 venus_hfi_queues_reinit(core);
592 }
593