GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / media / platform / qcom / venus / hfi.c
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
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
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
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
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
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
136 int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
137 {
138         return core->ops->core_trigger_ssr(core, type);
139 }
140
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
584 void hfi_destroy(struct venus_core *core)
585 {
586         venus_hfi_destroy(core);
587 }
588
589 void hfi_reinit(struct venus_core *core)
590 {
591         venus_hfi_queues_reinit(core);
592 }