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 	ret = core->ops->core_deinit(core);
108 
109 	if (!ret)
110 		core->state = CORE_UNINIT;
111 
112 unlock:
113 	mutex_unlock(&core->lock);
114 	return ret;
115 }
116 
117 int hfi_core_suspend(struct venus_core *core)
118 {
119 	if (core->state != CORE_INIT)
120 		return 0;
121 
122 	return core->ops->suspend(core);
123 }
124 
125 int hfi_core_resume(struct venus_core *core, bool force)
126 {
127 	if (!force && core->state != CORE_INIT)
128 		return 0;
129 
130 	return core->ops->resume(core);
131 }
132 
133 int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
134 {
135 	return core->ops->core_trigger_ssr(core, type);
136 }
137 
138 int hfi_core_ping(struct venus_core *core)
139 {
140 	int ret;
141 
142 	mutex_lock(&core->lock);
143 
144 	ret = core->ops->core_ping(core, 0xbeef);
145 	if (ret)
146 		goto unlock;
147 
148 	ret = wait_for_completion_timeout(&core->done, TIMEOUT);
149 	if (!ret) {
150 		ret = -ETIMEDOUT;
151 		goto unlock;
152 	}
153 	ret = 0;
154 	if (core->error != HFI_ERR_NONE)
155 		ret = -ENODEV;
156 unlock:
157 	mutex_unlock(&core->lock);
158 	return ret;
159 }
160 
161 static int wait_session_msg(struct venus_inst *inst)
162 {
163 	int ret;
164 
165 	ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
166 	if (!ret)
167 		return -ETIMEDOUT;
168 
169 	if (inst->error != HFI_ERR_NONE)
170 		return -EIO;
171 
172 	return 0;
173 }
174 
175 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
176 {
177 	struct venus_core *core = inst->core;
178 	bool max;
179 	int ret;
180 
181 	if (!ops)
182 		return -EINVAL;
183 
184 	inst->state = INST_UNINIT;
185 	init_completion(&inst->done);
186 	inst->ops = ops;
187 
188 	mutex_lock(&core->lock);
189 
190 	if (test_bit(0, &inst->core->sys_error)) {
191 		ret = -EIO;
192 		goto unlock;
193 	}
194 
195 	max = atomic_add_unless(&core->insts_count, 1,
196 				core->max_sessions_supported);
197 	if (!max) {
198 		ret = -EAGAIN;
199 	} else {
200 		list_add_tail(&inst->list, &core->instances);
201 		ret = 0;
202 	}
203 
204 unlock:
205 	mutex_unlock(&core->lock);
206 
207 	return ret;
208 }
209 EXPORT_SYMBOL_GPL(hfi_session_create);
210 
211 int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
212 {
213 	struct venus_core *core = inst->core;
214 	const struct hfi_ops *ops = core->ops;
215 	int ret;
216 
217 	/*
218 	 * If core shutdown is in progress or if we are in system
219 	 * recovery, return an error as during system error recovery
220 	 * session_init() can't pass successfully
221 	 */
222 	mutex_lock(&core->lock);
223 	if (!core->ops || test_bit(0, &inst->core->sys_error)) {
224 		mutex_unlock(&core->lock);
225 		return -EIO;
226 	}
227 	mutex_unlock(&core->lock);
228 
229 	if (inst->state != INST_UNINIT)
230 		return -EALREADY;
231 
232 	inst->hfi_codec = to_codec_type(pixfmt);
233 	reinit_completion(&inst->done);
234 
235 	ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
236 	if (ret)
237 		return ret;
238 
239 	ret = wait_session_msg(inst);
240 	if (ret)
241 		return ret;
242 
243 	inst->state = INST_INIT;
244 
245 	return 0;
246 }
247 EXPORT_SYMBOL_GPL(hfi_session_init);
248 
249 void hfi_session_destroy(struct venus_inst *inst)
250 {
251 	struct venus_core *core = inst->core;
252 
253 	mutex_lock(&core->lock);
254 	list_del_init(&inst->list);
255 	if (atomic_dec_and_test(&core->insts_count))
256 		wake_up_var(&core->insts_count);
257 	mutex_unlock(&core->lock);
258 }
259 EXPORT_SYMBOL_GPL(hfi_session_destroy);
260 
261 int hfi_session_deinit(struct venus_inst *inst)
262 {
263 	const struct hfi_ops *ops = inst->core->ops;
264 	int ret;
265 
266 	if (inst->state == INST_UNINIT)
267 		return 0;
268 
269 	if (inst->state < INST_INIT)
270 		return -EINVAL;
271 
272 	if (test_bit(0, &inst->core->sys_error))
273 		goto done;
274 
275 	reinit_completion(&inst->done);
276 
277 	ret = ops->session_end(inst);
278 	if (ret)
279 		return ret;
280 
281 	ret = wait_session_msg(inst);
282 	if (ret)
283 		return ret;
284 
285 done:
286 	inst->state = INST_UNINIT;
287 
288 	return 0;
289 }
290 EXPORT_SYMBOL_GPL(hfi_session_deinit);
291 
292 int hfi_session_start(struct venus_inst *inst)
293 {
294 	const struct hfi_ops *ops = inst->core->ops;
295 	int ret;
296 
297 	if (test_bit(0, &inst->core->sys_error))
298 		return -EIO;
299 
300 	if (inst->state != INST_LOAD_RESOURCES)
301 		return -EINVAL;
302 
303 	reinit_completion(&inst->done);
304 
305 	ret = ops->session_start(inst);
306 	if (ret)
307 		return ret;
308 
309 	ret = wait_session_msg(inst);
310 	if (ret)
311 		return ret;
312 
313 	inst->state = INST_START;
314 
315 	return 0;
316 }
317 EXPORT_SYMBOL_GPL(hfi_session_start);
318 
319 int hfi_session_stop(struct venus_inst *inst)
320 {
321 	const struct hfi_ops *ops = inst->core->ops;
322 	int ret;
323 
324 	if (test_bit(0, &inst->core->sys_error))
325 		return -EIO;
326 
327 	if (inst->state != INST_START)
328 		return -EINVAL;
329 
330 	reinit_completion(&inst->done);
331 
332 	ret = ops->session_stop(inst);
333 	if (ret)
334 		return ret;
335 
336 	ret = wait_session_msg(inst);
337 	if (ret)
338 		return ret;
339 
340 	inst->state = INST_STOP;
341 
342 	return 0;
343 }
344 EXPORT_SYMBOL_GPL(hfi_session_stop);
345 
346 int hfi_session_continue(struct venus_inst *inst)
347 {
348 	struct venus_core *core = inst->core;
349 
350 	if (test_bit(0, &inst->core->sys_error))
351 		return -EIO;
352 
353 	if (core->res->hfi_version == HFI_VERSION_1XX)
354 		return 0;
355 
356 	return core->ops->session_continue(inst);
357 }
358 EXPORT_SYMBOL_GPL(hfi_session_continue);
359 
360 int hfi_session_abort(struct venus_inst *inst)
361 {
362 	const struct hfi_ops *ops = inst->core->ops;
363 	int ret;
364 
365 	if (test_bit(0, &inst->core->sys_error))
366 		return -EIO;
367 
368 	reinit_completion(&inst->done);
369 
370 	ret = ops->session_abort(inst);
371 	if (ret)
372 		return ret;
373 
374 	ret = wait_session_msg(inst);
375 	if (ret)
376 		return ret;
377 
378 	return 0;
379 }
380 EXPORT_SYMBOL_GPL(hfi_session_abort);
381 
382 int hfi_session_load_res(struct venus_inst *inst)
383 {
384 	const struct hfi_ops *ops = inst->core->ops;
385 	int ret;
386 
387 	if (test_bit(0, &inst->core->sys_error))
388 		return -EIO;
389 
390 	if (inst->state != INST_INIT)
391 		return -EINVAL;
392 
393 	reinit_completion(&inst->done);
394 
395 	ret = ops->session_load_res(inst);
396 	if (ret)
397 		return ret;
398 
399 	ret = wait_session_msg(inst);
400 	if (ret)
401 		return ret;
402 
403 	inst->state = INST_LOAD_RESOURCES;
404 
405 	return 0;
406 }
407 
408 int hfi_session_unload_res(struct venus_inst *inst)
409 {
410 	const struct hfi_ops *ops = inst->core->ops;
411 	int ret;
412 
413 	if (test_bit(0, &inst->core->sys_error))
414 		return -EIO;
415 
416 	if (inst->state != INST_STOP)
417 		return -EINVAL;
418 
419 	reinit_completion(&inst->done);
420 
421 	ret = ops->session_release_res(inst);
422 	if (ret)
423 		return ret;
424 
425 	ret = wait_session_msg(inst);
426 	if (ret)
427 		return ret;
428 
429 	inst->state = INST_RELEASE_RESOURCES;
430 
431 	return 0;
432 }
433 EXPORT_SYMBOL_GPL(hfi_session_unload_res);
434 
435 int hfi_session_flush(struct venus_inst *inst, u32 type, bool block)
436 {
437 	const struct hfi_ops *ops = inst->core->ops;
438 	int ret;
439 
440 	if (test_bit(0, &inst->core->sys_error))
441 		return -EIO;
442 
443 	reinit_completion(&inst->done);
444 
445 	ret = ops->session_flush(inst, type);
446 	if (ret)
447 		return ret;
448 
449 	if (block) {
450 		ret = wait_session_msg(inst);
451 		if (ret)
452 			return ret;
453 	}
454 
455 	return 0;
456 }
457 EXPORT_SYMBOL_GPL(hfi_session_flush);
458 
459 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
460 {
461 	const struct hfi_ops *ops = inst->core->ops;
462 
463 	if (test_bit(0, &inst->core->sys_error))
464 		return -EIO;
465 
466 	return ops->session_set_buffers(inst, bd);
467 }
468 
469 int hfi_session_unset_buffers(struct venus_inst *inst,
470 			      struct hfi_buffer_desc *bd)
471 {
472 	const struct hfi_ops *ops = inst->core->ops;
473 	int ret;
474 
475 	if (test_bit(0, &inst->core->sys_error))
476 		return -EIO;
477 
478 	reinit_completion(&inst->done);
479 
480 	ret = ops->session_unset_buffers(inst, bd);
481 	if (ret)
482 		return ret;
483 
484 	if (!bd->response_required)
485 		return 0;
486 
487 	ret = wait_session_msg(inst);
488 	if (ret)
489 		return ret;
490 
491 	return 0;
492 }
493 
494 int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
495 			     union hfi_get_property *hprop)
496 {
497 	const struct hfi_ops *ops = inst->core->ops;
498 	int ret;
499 
500 	if (test_bit(0, &inst->core->sys_error))
501 		return -EIO;
502 
503 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
504 		return -EINVAL;
505 
506 	reinit_completion(&inst->done);
507 
508 	ret = ops->session_get_property(inst, ptype);
509 	if (ret)
510 		return ret;
511 
512 	ret = wait_session_msg(inst);
513 	if (ret)
514 		return ret;
515 
516 	*hprop = inst->hprop;
517 
518 	return 0;
519 }
520 EXPORT_SYMBOL_GPL(hfi_session_get_property);
521 
522 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
523 {
524 	const struct hfi_ops *ops = inst->core->ops;
525 
526 	if (test_bit(0, &inst->core->sys_error))
527 		return -EIO;
528 
529 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
530 		return -EINVAL;
531 
532 	return ops->session_set_property(inst, ptype, pdata);
533 }
534 EXPORT_SYMBOL_GPL(hfi_session_set_property);
535 
536 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
537 {
538 	const struct hfi_ops *ops = inst->core->ops;
539 
540 	if (test_bit(0, &inst->core->sys_error))
541 		return -EIO;
542 
543 	if (fd->buffer_type == HFI_BUFFER_INPUT)
544 		return ops->session_etb(inst, fd);
545 	else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
546 		 fd->buffer_type == HFI_BUFFER_OUTPUT2)
547 		return ops->session_ftb(inst, fd);
548 
549 	return -EINVAL;
550 }
551 EXPORT_SYMBOL_GPL(hfi_session_process_buf);
552 
553 irqreturn_t hfi_isr_thread(int irq, void *dev_id)
554 {
555 	struct venus_core *core = dev_id;
556 
557 	return core->ops->isr_thread(core);
558 }
559 
560 irqreturn_t hfi_isr(int irq, void *dev)
561 {
562 	struct venus_core *core = dev;
563 
564 	return core->ops->isr(core);
565 }
566 
567 int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
568 {
569 	int ret;
570 
571 	if (!ops)
572 		return -EINVAL;
573 
574 	atomic_set(&core->insts_count, 0);
575 	core->core_ops = ops;
576 	core->state = CORE_UNINIT;
577 	init_completion(&core->done);
578 	pkt_set_version(core->res->hfi_version);
579 	ret = venus_hfi_create(core);
580 
581 	return ret;
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