summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/chips-media/wave5/wave5-helper.c
blob: 8433ecab230cc2c3f12c157a6146c036ede91cf8 (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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Wave5 series multi-standard codec IP - decoder interface
 *
 * Copyright (C) 2021-2023 CHIPS&MEDIA INC
 */

#include "wave5-helper.h"

const char *state_to_str(enum vpu_instance_state state)
{
	switch (state) {
	case VPU_INST_STATE_NONE:
		return "NONE";
	case VPU_INST_STATE_OPEN:
		return "OPEN";
	case VPU_INST_STATE_INIT_SEQ:
		return "INIT_SEQ";
	case VPU_INST_STATE_PIC_RUN:
		return "PIC_RUN";
	case VPU_INST_STATE_STOP:
		return "STOP";
	default:
		return "UNKNOWN";
	}
}

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

	if (list_is_singular(&inst->list))
		wave5_vdi_free_sram(inst->dev);

	for (i = 0; i < inst->fbc_buf_count; i++)
		wave5_vpu_dec_reset_framebuffer(inst, i);

	wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
	v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
	if (inst->v4l2_fh.vdev) {
		v4l2_fh_del(&inst->v4l2_fh);
		v4l2_fh_exit(&inst->v4l2_fh);
	}
	list_del_init(&inst->list);
	ida_free(&inst->dev->inst_ida, inst->id);
	kfree(inst->codec_info);
	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 ret;

		ret = close_func(inst, &fail_res);
		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_src_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_src_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;

	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.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];
}

enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type)
{
	switch (v4l2_pix_fmt) {
	case V4L2_PIX_FMT_H264:
		return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC;
	case V4L2_PIX_FMT_HEVC:
		return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC;
	default:
		return STD_UNKNOWN;
	}
}

void wave5_return_bufs(struct vb2_queue *q, u32 state)
{
	struct vpu_instance *inst = vb2_get_drv_priv(q);
	struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
	struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl;
	struct vb2_v4l2_buffer *vbuf;

	for (;;) {
		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
			vbuf = v4l2_m2m_src_buf_remove(m2m_ctx);
		else
			vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx);
		if (!vbuf)
			return;
		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl);
		v4l2_m2m_buf_done(vbuf, state);
	}
}