File Index
Files and directories
Sign in
FILE

wave5-helper.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/chips-media/wave5/wave5-helper.c C
  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
 10#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3)
 11
 12const char *state_to_str(enum vpu_instance_state state)
 13{
 14	switch (state) {
 15	case VPU_INST_STATE_NONE:
 16		return "NONE";
 17	case VPU_INST_STATE_OPEN:
 18		return "OPEN";
 19	case VPU_INST_STATE_INIT_SEQ:
 20		return "INIT_SEQ";
 21	case VPU_INST_STATE_PIC_RUN:
 22		return "PIC_RUN";
 23	case VPU_INST_STATE_STOP:
 24		return "STOP";
 25	default:
 26		return "UNKNOWN";
 27	}
 28}
 29
 30int wave5_kfifo_alloc(struct vpu_instance *inst)
 31{
 32	return kfifo_alloc(&inst->irq_status, 16 * sizeof(int), GFP_KERNEL);
 33}
 34
 35void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp)
 36{
 37	int i;
 38
 39	/*
 40	 * For Wave515 SRAM memory is allocated at
 41	 * wave5_vpu_dec_register_device() and freed at
 42	 * wave5_vpu_dec_unregister_device().
 43	 */
 44	if (list_is_singular(&inst->list) &&
 45	    inst->dev->product_code != WAVE515_CODE)
 46		wave5_vdi_free_sram(inst->dev);
 47
 48	for (i = 0; i < inst->fbc_buf_count; i++)
 49		wave5_vpu_dec_reset_framebuffer(inst, i);
 50
 51	wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
 52	v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
 53	if (inst->v4l2_fh.vdev) {
 54		v4l2_fh_del(&inst->v4l2_fh, filp);
 55		v4l2_fh_exit(&inst->v4l2_fh);
 56	}
 57	kfifo_free(&inst->irq_status);
 58	ida_free(&inst->dev->inst_ida, inst->id);
 59	kfree(inst->codec_info);
 60	kfree(inst);
 61}
 62
 63int wave5_vpu_release_device(struct file *filp,
 64			     int (*close_func)(struct vpu_instance *inst, u32 *fail_res),
 65			     char *name)
 66{
 67	struct vpu_instance *inst = file_to_vpu_inst(filp);
 68	int ret = 0;
 69	unsigned long flags;
 70
 71	v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
 72	/*
 73	 * To prevent Null reference exception, the existing irq handler were
 74	 * separated to two modules.
 75	 * One is to queue interrupt reason into the irq handler,
 76	 * the other is irq_thread to call the wave5_vpu_dec_finish_decode
 77	 * to get decoded frame.
 78	 * The list of instances should be protected between all flow of the
 79	 * decoding process, but to protect the list in the irq_handler, spin lock
 80	 * should be used, and mutex should be used in the irq_thread because spin lock
 81	 * is not able to be used because mutex is already being used
 82	 * in the wave5_vpu_dec_finish_decode.
 83	 * So the spin lock and mutex were used to protect the list in the release function.
 84	 */
 85	ret = mutex_lock_interruptible(&inst->dev->irq_lock);
 86	if (ret)
 87		return ret;
 88	spin_lock_irqsave(&inst->dev->irq_spinlock, flags);
 89	list_del_init(&inst->list);
 90	spin_unlock_irqrestore(&inst->dev->irq_spinlock, flags);
 91	mutex_unlock(&inst->dev->irq_lock);
 92	if (inst->state != VPU_INST_STATE_NONE) {
 93		u32 fail_res;
 94
 95		ret = close_func(inst, &fail_res);
 96		if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) {
 97			dev_err(inst->dev->dev, "%s close failed, device is still running\n",
 98				name);
 99			return -EBUSY;
100		}
101		if (ret && ret != -EIO) {
102			dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret);
103			return ret;
104		}
105	}
106
107	wave5_cleanup_instance(inst, filp);
108
109	return ret;
110}
111
112int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
113			 const struct vb2_ops *ops)
114{
115	struct vpu_instance *inst = priv;
116	int ret;
117
118	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
119	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
120	src_vq->mem_ops = &vb2_dma_contig_memops;
121	src_vq->ops = ops;
122	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
123	src_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
124	src_vq->drv_priv = inst;
125	src_vq->lock = &inst->dev->dev_lock;
126	src_vq->dev = inst->dev->v4l2_dev.dev;
127	ret = vb2_queue_init(src_vq);
128	if (ret)
129		return ret;
130
131	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
132	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
133	dst_vq->mem_ops = &vb2_dma_contig_memops;
134	dst_vq->ops = ops;
135	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
136	dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
137	dst_vq->drv_priv = inst;
138	dst_vq->lock = &inst->dev->dev_lock;
139	dst_vq->dev = inst->dev->v4l2_dev.dev;
140	ret = vb2_queue_init(dst_vq);
141	if (ret)
142		return ret;
143
144	return 0;
145}
146
147int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
148{
149	struct vpu_instance *inst = wave5_to_vpu_inst(fh);
150	bool is_decoder = inst->type == VPU_INST_TYPE_DEC;
151
152	dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__,
153		is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags);
154
155	switch (sub->type) {
156	case V4L2_EVENT_EOS:
157		return v4l2_event_subscribe(fh, sub, 0, NULL);
158	case V4L2_EVENT_SOURCE_CHANGE:
159		if (is_decoder)
160			return v4l2_src_change_event_subscribe(fh, sub);
161		return -EINVAL;
162	case V4L2_EVENT_CTRL:
163		return v4l2_ctrl_subscribe_event(fh, sub);
164	default:
165		return -EINVAL;
166	}
167}
168
169int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
170{
171	struct vpu_instance *inst = file_to_vpu_inst(file);
172	int i;
173
174	f->fmt.pix_mp.width = inst->src_fmt.width;
175	f->fmt.pix_mp.height = inst->src_fmt.height;
176	f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
177	f->fmt.pix_mp.field = inst->src_fmt.field;
178	f->fmt.pix_mp.flags = inst->src_fmt.flags;
179	f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
180	for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
181		f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
182		f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
183	}
184
185	f->fmt.pix_mp.colorspace = inst->colorspace;
186	f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
187	f->fmt.pix_mp.quantization = inst->quantization;
188	f->fmt.pix_mp.xfer_func = inst->xfer_func;
189
190	return 0;
191}
192
193const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt,
194					    const struct vpu_format fmt_list[MAX_FMTS])
195{
196	unsigned int index;
197
198	for (index = 0; index < MAX_FMTS; index++) {
199		if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt)
200			return &fmt_list[index];
201	}
202
203	return NULL;
204}
205
206const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
207						   const struct vpu_format fmt_list[MAX_FMTS])
208{
209	if (idx >= MAX_FMTS)
210		return NULL;
211
212	if (!fmt_list[idx].v4l2_pix_fmt)
213		return NULL;
214
215	return &fmt_list[idx];
216}
217
218enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type)
219{
220	switch (v4l2_pix_fmt) {
221	case V4L2_PIX_FMT_H264:
222		return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC;
223	case V4L2_PIX_FMT_HEVC:
224		return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC;
225	default:
226		return STD_UNKNOWN;
227	}
228}
229
230void wave5_return_bufs(struct vb2_queue *q, u32 state)
231{
232	struct vpu_instance *inst = vb2_get_drv_priv(q);
233	struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
234	struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl;
235	struct vb2_v4l2_buffer *vbuf;
236
237	for (;;) {
238		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
239			vbuf = v4l2_m2m_src_buf_remove(m2m_ctx);
240		else
241			vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx);
242		if (!vbuf)
243			return;
244		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl);
245		v4l2_m2m_buf_done(vbuf, state);
246	}
247}
248
249void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
250			  int pix_fmt_type,
251			  unsigned int width,
252			  unsigned int height,
253			  const struct v4l2_frmsize_stepwise *frmsize)
254{
255	v4l2_apply_frmsize_constraints(&width, &height, frmsize);
256
257	if (pix_fmt_type == VPU_FMT_TYPE_CODEC) {
258		pix_mp->width = width;
259		pix_mp->height = height;
260		pix_mp->num_planes = 1;
261		pix_mp->plane_fmt[0].bytesperline = 0;
262		pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height),
263						     pix_mp->plane_fmt[0].sizeimage);
264	} else {
265		v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height);
266	}
267	pix_mp->flags = 0;
268	pix_mp->field = V4L2_FIELD_NONE;
269}
~/ Read-only file preview.