FILE
wave5-helper.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/chips-media/wave5/wave5-helper.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.