xref: /linux/drivers/media/platform/qcom/venus/hfi.c (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
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 }
593