File Index
Files and directories
Sign in
FILE

hfi.c

File preview with syntax highlighting.

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