summaryrefslogtreecommitdiff
path: root/drivers/media/platform/chips-media/wave5/wave5-helper.c
blob: 09dfb20e9a20d50a736f9e8e1f3c9447457ebb25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Wave5 series multi-standard codec IP - decoder interface
 *
 * Copyright (C) 2021 CHIPS&MEDIA INC
 */

#include "wave5-helper.h"

void wave5_cleanup_instance(struct vpu_instance *inst)
{
	int i;

	for (i = 0; i < inst->dst_buf_count; i++)
		wave5_vdi_free_dma_memory(inst->dev, &inst->frame_vbuf[i]);

	wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
	v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
	if (inst->v4l2_m2m_dev != NULL)
		v4l2_m2m_release(inst->v4l2_m2m_dev);
	if (inst->v4l2_fh.vdev != NULL) {
		v4l2_fh_del(&inst->v4l2_fh);
		v4l2_fh_exit(&inst->v4l2_fh);
	}
	list_del_init(&inst->list);
	kfifo_free(&inst->irq_status);
	ida_free(&inst->dev->inst_ida, inst->id);
	kfree(inst);
}

int wave5_vpu_release_device(struct file *filp,
			     int (*close_func)(struct vpu_instance *inst, u32 *fail_res),
			     char *name)
{
	struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);

	v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
	if (inst->state != VPU_INST_STATE_NONE) {
		u32 fail_res;
		int retry_count = 10;
		int ret;

		do {
			fail_res = 0;
			ret = close_func(inst, &fail_res);
			if (ret && ret != -EIO)
				break;
			if (fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING)
				break;
			if (!wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT/10))
				break;
		} while (--retry_count);

		if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) {
			dev_err(inst->dev->dev, "%s close failed, device is still running\n",
				 name);
			return -EBUSY;
		}
		if (ret && ret != -EIO) {
			dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret);
			return ret;
		}
	}

	wave5_cleanup_instance(inst);

	return 0;
}

int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
			 const struct vb2_ops *ops)
{
	struct vpu_instance *inst = priv;
	int ret;

	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
	src_vq->mem_ops = &vb2_dma_contig_memops;
	src_vq->ops = ops;
	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
	src_vq->buf_struct_size = sizeof(struct vpu_buffer);
	src_vq->drv_priv = inst;
	src_vq->lock = &inst->dev->dev_lock;
	src_vq->dev = inst->dev->v4l2_dev.dev;
	ret = vb2_queue_init(src_vq);
	if (ret)
		return ret;

	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
	dst_vq->mem_ops = &vb2_dma_contig_memops;
	dst_vq->ops = ops;
	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
	dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
	dst_vq->drv_priv = inst;
	dst_vq->lock = &inst->dev->dev_lock;
	dst_vq->dev = inst->dev->v4l2_dev.dev;
	ret = vb2_queue_init(dst_vq);
	if (ret)
		return ret;

	return 0;
}

int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
{
	struct vpu_instance *inst = wave5_to_vpu_inst(fh);
	bool is_decoder = inst->type == VPU_INST_TYPE_DEC;

	dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__,
		is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags);

	switch (sub->type) {
	case V4L2_EVENT_EOS:
		return v4l2_event_subscribe(fh, sub, 0, NULL);
	case V4L2_EVENT_SOURCE_CHANGE:
		if (is_decoder)
			return v4l2_src_change_event_subscribe(fh, sub);
		return -EINVAL;
	case V4L2_EVENT_CTRL:
		return v4l2_ctrl_subscribe_event(fh, sub);
	default:
		return -EINVAL;
	}
}

int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
	struct vpu_instance *inst = wave5_to_vpu_inst(fh);
	int i;

	if (inst->state >= VPU_INST_STATE_INIT_SEQ){
		f->fmt.pix_mp.width = inst->src_fmt.width - inst->crop_rect.right;
		f->fmt.pix_mp.height = inst->src_fmt.height - inst->crop_rect.bottom;
	} else {
		f->fmt.pix_mp.width = inst->src_fmt.width;
		f->fmt.pix_mp.height = inst->src_fmt.height;
	}
	f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
	f->fmt.pix_mp.field = inst->src_fmt.field;
	f->fmt.pix_mp.flags = inst->src_fmt.flags;
	f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
	for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
		f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
		f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
	}

	f->fmt.pix_mp.colorspace = inst->colorspace;
	f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
	f->fmt.pix_mp.hsv_enc = inst->hsv_enc;
	f->fmt.pix_mp.quantization = inst->quantization;
	f->fmt.pix_mp.xfer_func = inst->xfer_func;

	return 0;
}

const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt,
					    const struct vpu_format fmt_list[MAX_FMTS])
{
	unsigned int index;

	for (index = 0; index < MAX_FMTS; index++) {
		if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt)
			return &fmt_list[index];
	}

	return NULL;
}

const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
						   const struct vpu_format fmt_list[MAX_FMTS])
{
	if (idx >= MAX_FMTS)
		return NULL;

	if (!fmt_list[idx].v4l2_pix_fmt)
		return NULL;

	return &fmt_list[idx];
}