1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2/*
3 * Wave5 series multi-standard codec IP - decoder interface
4 *
5 * Copyright (C) 2021-2023 CHIPS&MEDIA INC
6 */
7
8#include "wave5-helper.h"
9
10const char *state_to_str(enum vpu_instance_state state)
11{
12	switch (state) {
13	case VPU_INST_STATE_NONE:
14		return "NONE";
15	case VPU_INST_STATE_OPEN:
16		return "OPEN";
17	case VPU_INST_STATE_INIT_SEQ:
18		return "INIT_SEQ";
19	case VPU_INST_STATE_PIC_RUN:
20		return "PIC_RUN";
21	case VPU_INST_STATE_STOP:
22		return "STOP";
23	default:
24		return "UNKNOWN";
25	}
26}
27
28void wave5_cleanup_instance(struct vpu_instance *inst)
29{
30	int i;
31
32	if (list_is_singular(&inst->list))
33		wave5_vdi_free_sram(inst->dev);
34
35	for (i = 0; i < inst->fbc_buf_count; i++)
36		wave5_vpu_dec_reset_framebuffer(inst, i);
37
38	wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
39	v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
40	if (inst->v4l2_fh.vdev) {
41		v4l2_fh_del(&inst->v4l2_fh);
42		v4l2_fh_exit(&inst->v4l2_fh);
43	}
44	list_del_init(&inst->list);
45	ida_free(&inst->dev->inst_ida, inst->id);
46	kfree(inst->codec_info);
47	kfree(inst);
48}
49
50int wave5_vpu_release_device(struct file *filp,
51			     int (*close_func)(struct vpu_instance *inst, u32 *fail_res),
52			     char *name)
53{
54	struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);
55
56	v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
57	if (inst->state != VPU_INST_STATE_NONE) {
58		u32 fail_res;
59		int ret;
60
61		ret = close_func(inst, &fail_res);
62		if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) {
63			dev_err(inst->dev->dev, "%s close failed, device is still running\n",
64				name);
65			return -EBUSY;
66		}
67		if (ret && ret != -EIO) {
68			dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret);
69			return ret;
70		}
71	}
72
73	wave5_cleanup_instance(inst);
74
75	return 0;
76}
77
78int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
79			 const struct vb2_ops *ops)
80{
81	struct vpu_instance *inst = priv;
82	int ret;
83
84	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
85	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
86	src_vq->mem_ops = &vb2_dma_contig_memops;
87	src_vq->ops = ops;
88	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
89	src_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
90	src_vq->drv_priv = inst;
91	src_vq->lock = &inst->dev->dev_lock;
92	src_vq->dev = inst->dev->v4l2_dev.dev;
93	ret = vb2_queue_init(src_vq);
94	if (ret)
95		return ret;
96
97	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
98	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
99	dst_vq->mem_ops = &vb2_dma_contig_memops;
100	dst_vq->ops = ops;
101	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
102	dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
103	dst_vq->drv_priv = inst;
104	dst_vq->lock = &inst->dev->dev_lock;
105	dst_vq->dev = inst->dev->v4l2_dev.dev;
106	ret = vb2_queue_init(dst_vq);
107	if (ret)
108		return ret;
109
110	return 0;
111}
112
113int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
114{
115	struct vpu_instance *inst = wave5_to_vpu_inst(fh);
116	bool is_decoder = inst->type == VPU_INST_TYPE_DEC;
117
118	dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__,
119		is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags);
120
121	switch (sub->type) {
122	case V4L2_EVENT_EOS:
123		return v4l2_event_subscribe(fh, sub, 0, NULL);
124	case V4L2_EVENT_SOURCE_CHANGE:
125		if (is_decoder)
126			return v4l2_src_change_event_subscribe(fh, sub);
127		return -EINVAL;
128	case V4L2_EVENT_CTRL:
129		return v4l2_ctrl_subscribe_event(fh, sub);
130	default:
131		return -EINVAL;
132	}
133}
134
135int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
136{
137	struct vpu_instance *inst = wave5_to_vpu_inst(fh);
138	int i;
139
140	f->fmt.pix_mp.width = inst->src_fmt.width;
141	f->fmt.pix_mp.height = inst->src_fmt.height;
142	f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
143	f->fmt.pix_mp.field = inst->src_fmt.field;
144	f->fmt.pix_mp.flags = inst->src_fmt.flags;
145	f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
146	for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
147		f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
148		f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
149	}
150
151	f->fmt.pix_mp.colorspace = inst->colorspace;
152	f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
153	f->fmt.pix_mp.quantization = inst->quantization;
154	f->fmt.pix_mp.xfer_func = inst->xfer_func;
155
156	return 0;
157}
158
159const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt,
160					    const struct vpu_format fmt_list[MAX_FMTS])
161{
162	unsigned int index;
163
164	for (index = 0; index < MAX_FMTS; index++) {
165		if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt)
166			return &fmt_list[index];
167	}
168
169	return NULL;
170}
171
172const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
173						   const struct vpu_format fmt_list[MAX_FMTS])
174{
175	if (idx >= MAX_FMTS)
176		return NULL;
177
178	if (!fmt_list[idx].v4l2_pix_fmt)
179		return NULL;
180
181	return &fmt_list[idx];
182}
183
184enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type)
185{
186	switch (v4l2_pix_fmt) {
187	case V4L2_PIX_FMT_H264:
188		return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC;
189	case V4L2_PIX_FMT_HEVC:
190		return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC;
191	default:
192		return STD_UNKNOWN;
193	}
194}
195
196void wave5_return_bufs(struct vb2_queue *q, u32 state)
197{
198	struct vpu_instance *inst = vb2_get_drv_priv(q);
199	struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
200	struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl;
201	struct vb2_v4l2_buffer *vbuf;
202
203	for (;;) {
204		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
205			vbuf = v4l2_m2m_src_buf_remove(m2m_ctx);
206		else
207			vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx);
208		if (!vbuf)
209			return;
210		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl);
211		v4l2_m2m_buf_done(vbuf, state);
212	}
213}
214