1256bf813SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only 2256bf813SHans Verkuil /* 3256bf813SHans Verkuil * A virtual codec example device. 4256bf813SHans Verkuil * 5256bf813SHans Verkuil * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 6256bf813SHans Verkuil * 7256bf813SHans Verkuil * This is a virtual codec device driver for testing the codec framework. 8256bf813SHans Verkuil * It simulates a device that uses memory buffers for both source and 9256bf813SHans Verkuil * destination and encodes or decodes the data. 10256bf813SHans Verkuil */ 11256bf813SHans Verkuil 12256bf813SHans Verkuil #include <linux/module.h> 13256bf813SHans Verkuil #include <linux/delay.h> 14256bf813SHans Verkuil #include <linux/fs.h> 15256bf813SHans Verkuil #include <linux/sched.h> 16256bf813SHans Verkuil #include <linux/slab.h> 17256bf813SHans Verkuil 18256bf813SHans Verkuil #include <linux/platform_device.h> 19256bf813SHans Verkuil #include <media/v4l2-mem2mem.h> 20256bf813SHans Verkuil #include <media/v4l2-device.h> 21256bf813SHans Verkuil #include <media/v4l2-ioctl.h> 22256bf813SHans Verkuil #include <media/v4l2-ctrls.h> 23256bf813SHans Verkuil #include <media/v4l2-event.h> 24256bf813SHans Verkuil #include <media/videobuf2-vmalloc.h> 25256bf813SHans Verkuil 26cd12b401SHans Verkuil #include "codec-v4l2-fwht.h" 27256bf813SHans Verkuil 28256bf813SHans Verkuil MODULE_DESCRIPTION("Virtual codec device"); 29256bf813SHans Verkuil MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); 30256bf813SHans Verkuil MODULE_LICENSE("GPL v2"); 31256bf813SHans Verkuil 32256bf813SHans Verkuil static bool multiplanar; 33256bf813SHans Verkuil module_param(multiplanar, bool, 0444); 34256bf813SHans Verkuil MODULE_PARM_DESC(multiplanar, 35256bf813SHans Verkuil " use multi-planar API instead of single-planar API"); 36256bf813SHans Verkuil 37256bf813SHans Verkuil static unsigned int debug; 38256bf813SHans Verkuil module_param(debug, uint, 0644); 39256bf813SHans Verkuil MODULE_PARM_DESC(debug, " activates debug info"); 40256bf813SHans Verkuil 41256bf813SHans Verkuil #define VICODEC_NAME "vicodec" 42256bf813SHans Verkuil #define MAX_WIDTH 4096U 43256bf813SHans Verkuil #define MIN_WIDTH 640U 44256bf813SHans Verkuil #define MAX_HEIGHT 2160U 457cf7b2e9SHans Verkuil #define MIN_HEIGHT 360U 46256bf813SHans Verkuil 47256bf813SHans Verkuil #define dprintk(dev, fmt, arg...) \ 48256bf813SHans Verkuil v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) 49256bf813SHans Verkuil 50256bf813SHans Verkuil 5129a7a5e9SHans Verkuil struct pixfmt_info { 5229a7a5e9SHans Verkuil u32 id; 5329a7a5e9SHans Verkuil unsigned int bytesperline_mult; 5429a7a5e9SHans Verkuil unsigned int sizeimage_mult; 5529a7a5e9SHans Verkuil unsigned int sizeimage_div; 5629a7a5e9SHans Verkuil unsigned int luma_step; 5729a7a5e9SHans Verkuil unsigned int chroma_step; 5829a7a5e9SHans Verkuil /* Chroma plane subsampling */ 5929a7a5e9SHans Verkuil unsigned int width_div; 6029a7a5e9SHans Verkuil unsigned int height_div; 6129a7a5e9SHans Verkuil }; 6229a7a5e9SHans Verkuil 63cd12b401SHans Verkuil static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { 648c1d02f1SDafna Hirschfeld V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 6529a7a5e9SHans Verkuil }; 6629a7a5e9SHans Verkuil 672495f39cSDafna Hirschfeld static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { 682495f39cSDafna Hirschfeld V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 692495f39cSDafna Hirschfeld }; 702495f39cSDafna Hirschfeld 71256bf813SHans Verkuil static void vicodec_dev_release(struct device *dev) 72256bf813SHans Verkuil { 73256bf813SHans Verkuil } 74256bf813SHans Verkuil 75256bf813SHans Verkuil static struct platform_device vicodec_pdev = { 76256bf813SHans Verkuil .name = VICODEC_NAME, 77256bf813SHans Verkuil .dev.release = vicodec_dev_release, 78256bf813SHans Verkuil }; 79256bf813SHans Verkuil 80256bf813SHans Verkuil /* Per-queue, driver-specific private data */ 81256bf813SHans Verkuil struct vicodec_q_data { 829e812549SDafna Hirschfeld unsigned int coded_width; 839e812549SDafna Hirschfeld unsigned int coded_height; 849e812549SDafna Hirschfeld unsigned int visible_width; 859e812549SDafna Hirschfeld unsigned int visible_height; 86256bf813SHans Verkuil unsigned int sizeimage; 878307f0abSHans Verkuil unsigned int vb2_sizeimage; 88256bf813SHans Verkuil unsigned int sequence; 89cd12b401SHans Verkuil const struct v4l2_fwht_pixfmt_info *info; 90256bf813SHans Verkuil }; 91256bf813SHans Verkuil 92256bf813SHans Verkuil enum { 93256bf813SHans Verkuil V4L2_M2M_SRC = 0, 94256bf813SHans Verkuil V4L2_M2M_DST = 1, 95256bf813SHans Verkuil }; 96256bf813SHans Verkuil 97c022a4a9SDafna Hirschfeld struct vicodec_dev_instance { 98c022a4a9SDafna Hirschfeld struct video_device vfd; 99c022a4a9SDafna Hirschfeld struct mutex mutex; 100c022a4a9SDafna Hirschfeld spinlock_t lock; 101c022a4a9SDafna Hirschfeld struct v4l2_m2m_dev *m2m_dev; 102c022a4a9SDafna Hirschfeld }; 103c022a4a9SDafna Hirschfeld 104256bf813SHans Verkuil struct vicodec_dev { 105256bf813SHans Verkuil struct v4l2_device v4l2_dev; 106c022a4a9SDafna Hirschfeld struct vicodec_dev_instance stateful_enc; 107c022a4a9SDafna Hirschfeld struct vicodec_dev_instance stateful_dec; 108fde649b4SDafna Hirschfeld struct vicodec_dev_instance stateless_dec; 109256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 110256bf813SHans Verkuil struct media_device mdev; 111256bf813SHans Verkuil #endif 112256bf813SHans Verkuil 113256bf813SHans Verkuil }; 114256bf813SHans Verkuil 115256bf813SHans Verkuil struct vicodec_ctx { 116256bf813SHans Verkuil struct v4l2_fh fh; 117256bf813SHans Verkuil struct vicodec_dev *dev; 118256bf813SHans Verkuil bool is_enc; 119fde649b4SDafna Hirschfeld bool is_stateless; 120256bf813SHans Verkuil spinlock_t *lock; 121256bf813SHans Verkuil 122256bf813SHans Verkuil struct v4l2_ctrl_handler hdl; 123256bf813SHans Verkuil 124256bf813SHans Verkuil /* Source and destination queue data */ 125256bf813SHans Verkuil struct vicodec_q_data q_data[2]; 126cd12b401SHans Verkuil struct v4l2_fwht_state state; 127cd12b401SHans Verkuil 128256bf813SHans Verkuil u32 cur_buf_offset; 129256bf813SHans Verkuil u32 comp_max_size; 130256bf813SHans Verkuil u32 comp_size; 131ddc1b085SDafna Hirschfeld u32 header_size; 132256bf813SHans Verkuil u32 comp_magic_cnt; 133256bf813SHans Verkuil bool comp_has_frame; 134256bf813SHans Verkuil bool comp_has_next_frame; 1353b15f68eSDafna Hirschfeld bool first_source_change_sent; 1363b15f68eSDafna Hirschfeld bool source_changed; 137256bf813SHans Verkuil }; 138256bf813SHans Verkuil 139d17589afSHans Verkuil static const struct v4l2_event vicodec_eos_event = { 140d17589afSHans Verkuil .type = V4L2_EVENT_EOS 141d17589afSHans Verkuil }; 142d17589afSHans Verkuil 143256bf813SHans Verkuil static inline struct vicodec_ctx *file2ctx(struct file *file) 144256bf813SHans Verkuil { 145256bf813SHans Verkuil return container_of(file->private_data, struct vicodec_ctx, fh); 146256bf813SHans Verkuil } 147256bf813SHans Verkuil 148256bf813SHans Verkuil static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, 149256bf813SHans Verkuil enum v4l2_buf_type type) 150256bf813SHans Verkuil { 151256bf813SHans Verkuil switch (type) { 152256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 153256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 154256bf813SHans Verkuil return &ctx->q_data[V4L2_M2M_SRC]; 155256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE: 156256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 157256bf813SHans Verkuil return &ctx->q_data[V4L2_M2M_DST]; 158256bf813SHans Verkuil default: 159256bf813SHans Verkuil break; 160256bf813SHans Verkuil } 161256bf813SHans Verkuil return NULL; 162256bf813SHans Verkuil } 163256bf813SHans Verkuil 16486764b88SDafna Hirschfeld static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info, 16586764b88SDafna Hirschfeld struct v4l2_fwht_state *state) 16686764b88SDafna Hirschfeld { 16786764b88SDafna Hirschfeld int plane_idx; 16886764b88SDafna Hirschfeld u8 *p_ref = state->ref_frame.buf; 16986764b88SDafna Hirschfeld unsigned int cap_stride = state->stride; 17086764b88SDafna Hirschfeld unsigned int ref_stride = state->ref_stride; 17186764b88SDafna Hirschfeld 17286764b88SDafna Hirschfeld for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) { 17386764b88SDafna Hirschfeld int i; 17486764b88SDafna Hirschfeld unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ? 17586764b88SDafna Hirschfeld info->height_div : 1; 17686764b88SDafna Hirschfeld const u8 *row_cap = cap; 17786764b88SDafna Hirschfeld u8 *row_ref = p_ref; 17886764b88SDafna Hirschfeld 17986764b88SDafna Hirschfeld if (info->planes_num == 3 && plane_idx == 1) { 18086764b88SDafna Hirschfeld cap_stride /= 2; 18186764b88SDafna Hirschfeld ref_stride /= 2; 18286764b88SDafna Hirschfeld } 18386764b88SDafna Hirschfeld 18486764b88SDafna Hirschfeld if (plane_idx == 1 && 18586764b88SDafna Hirschfeld (info->id == V4L2_PIX_FMT_NV24 || 18686764b88SDafna Hirschfeld info->id == V4L2_PIX_FMT_NV42)) { 18786764b88SDafna Hirschfeld cap_stride *= 2; 18886764b88SDafna Hirschfeld ref_stride *= 2; 18986764b88SDafna Hirschfeld } 19086764b88SDafna Hirschfeld 19186764b88SDafna Hirschfeld for (i = 0; i < state->visible_height / h_div; i++) { 19286764b88SDafna Hirschfeld memcpy(row_ref, row_cap, ref_stride); 19386764b88SDafna Hirschfeld row_ref += ref_stride; 19486764b88SDafna Hirschfeld row_cap += cap_stride; 19586764b88SDafna Hirschfeld } 19686764b88SDafna Hirschfeld cap += cap_stride * (state->coded_height / h_div); 19786764b88SDafna Hirschfeld p_ref += ref_stride * (state->coded_height / h_div); 19886764b88SDafna Hirschfeld } 19986764b88SDafna Hirschfeld } 20086764b88SDafna Hirschfeld 20192dc64d4SDafna Hirschfeld static bool validate_by_version(unsigned int flags, unsigned int version) 20292dc64d4SDafna Hirschfeld { 2033abfc314SHans Verkuil if (!version || version > V4L2_FWHT_VERSION) 20492dc64d4SDafna Hirschfeld return false; 20592dc64d4SDafna Hirschfeld 20692dc64d4SDafna Hirschfeld if (version >= 2) { 20792dc64d4SDafna Hirschfeld unsigned int components_num = 1 + 2083abfc314SHans Verkuil ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> 2093abfc314SHans Verkuil V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); 2103abfc314SHans Verkuil unsigned int pixenc = flags & V4L2_FWHT_FL_PIXENC_MSK; 21192dc64d4SDafna Hirschfeld 21292dc64d4SDafna Hirschfeld if (components_num == 0 || components_num > 4 || !pixenc) 21392dc64d4SDafna Hirschfeld return false; 21492dc64d4SDafna Hirschfeld } 21592dc64d4SDafna Hirschfeld return true; 21692dc64d4SDafna Hirschfeld } 21792dc64d4SDafna Hirschfeld 218997deb81SDafna Hirschfeld static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params, 219997deb81SDafna Hirschfeld const struct v4l2_fwht_pixfmt_info *cur_info) 220997deb81SDafna Hirschfeld { 221997deb81SDafna Hirschfeld unsigned int width_div = 2223abfc314SHans Verkuil (params->flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 223997deb81SDafna Hirschfeld unsigned int height_div = 2243abfc314SHans Verkuil (params->flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 225997deb81SDafna Hirschfeld unsigned int components_num = 3; 226997deb81SDafna Hirschfeld unsigned int pixenc = 0; 227997deb81SDafna Hirschfeld 228997deb81SDafna Hirschfeld if (params->version < 3) 229997deb81SDafna Hirschfeld return false; 230997deb81SDafna Hirschfeld 2313abfc314SHans Verkuil components_num = 1 + ((params->flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> 2323abfc314SHans Verkuil V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); 2333abfc314SHans Verkuil pixenc = (params->flags & V4L2_FWHT_FL_PIXENC_MSK); 234997deb81SDafna Hirschfeld if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, 235997deb81SDafna Hirschfeld components_num, pixenc)) 236997deb81SDafna Hirschfeld return true; 237997deb81SDafna Hirschfeld return false; 238997deb81SDafna Hirschfeld } 239997deb81SDafna Hirschfeld 240997deb81SDafna Hirschfeld 241997deb81SDafna Hirschfeld static void update_state_from_header(struct vicodec_ctx *ctx) 242997deb81SDafna Hirschfeld { 243997deb81SDafna Hirschfeld const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; 244997deb81SDafna Hirschfeld 245997deb81SDafna Hirschfeld ctx->state.visible_width = ntohl(p_hdr->width); 246997deb81SDafna Hirschfeld ctx->state.visible_height = ntohl(p_hdr->height); 247997deb81SDafna Hirschfeld ctx->state.colorspace = ntohl(p_hdr->colorspace); 248997deb81SDafna Hirschfeld ctx->state.xfer_func = ntohl(p_hdr->xfer_func); 249997deb81SDafna Hirschfeld ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); 250997deb81SDafna Hirschfeld ctx->state.quantization = ntohl(p_hdr->quantization); 251997deb81SDafna Hirschfeld } 252997deb81SDafna Hirschfeld 253256bf813SHans Verkuil static int device_process(struct vicodec_ctx *ctx, 254b9bbbbfeSDafna Hirschfeld struct vb2_v4l2_buffer *src_vb, 255b9bbbbfeSDafna Hirschfeld struct vb2_v4l2_buffer *dst_vb) 256256bf813SHans Verkuil { 257256bf813SHans Verkuil struct vicodec_dev *dev = ctx->dev; 258cd12b401SHans Verkuil struct v4l2_fwht_state *state = &ctx->state; 259b9bbbbfeSDafna Hirschfeld u8 *p_src, *p_dst; 260997deb81SDafna Hirschfeld int ret = 0; 261256bf813SHans Verkuil 262997deb81SDafna Hirschfeld if (ctx->is_enc || ctx->is_stateless) 263b9bbbbfeSDafna Hirschfeld p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0); 264256bf813SHans Verkuil else 265b9bbbbfeSDafna Hirschfeld p_src = state->compressed_frame; 266997deb81SDafna Hirschfeld 267997deb81SDafna Hirschfeld if (ctx->is_stateless) { 268997deb81SDafna Hirschfeld struct media_request *src_req = src_vb->vb2_buf.req_obj.req; 269997deb81SDafna Hirschfeld 270997deb81SDafna Hirschfeld ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl); 271997deb81SDafna Hirschfeld if (ret) 272997deb81SDafna Hirschfeld return ret; 273997deb81SDafna Hirschfeld update_state_from_header(ctx); 274997deb81SDafna Hirschfeld 275997deb81SDafna Hirschfeld ctx->state.header.size = 276997deb81SDafna Hirschfeld htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0)); 277997deb81SDafna Hirschfeld /* 278997deb81SDafna Hirschfeld * set the reference buffer from the reference timestamp 279997deb81SDafna Hirschfeld * only if this is a P-frame 280997deb81SDafna Hirschfeld */ 2813abfc314SHans Verkuil if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) { 282997deb81SDafna Hirschfeld struct vb2_buffer *ref_vb2_buf; 283997deb81SDafna Hirschfeld int ref_buf_idx; 284997deb81SDafna Hirschfeld struct vb2_queue *vq_cap = 285997deb81SDafna Hirschfeld v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 286997deb81SDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 287997deb81SDafna Hirschfeld 288997deb81SDafna Hirschfeld ref_buf_idx = vb2_find_timestamp(vq_cap, 289997deb81SDafna Hirschfeld ctx->state.ref_frame_ts, 0); 290997deb81SDafna Hirschfeld if (ref_buf_idx < 0) 291997deb81SDafna Hirschfeld return -EINVAL; 292997deb81SDafna Hirschfeld 293997deb81SDafna Hirschfeld ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; 294997deb81SDafna Hirschfeld if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) 295997deb81SDafna Hirschfeld ret = -EINVAL; 296997deb81SDafna Hirschfeld ctx->state.ref_frame.buf = 297997deb81SDafna Hirschfeld vb2_plane_vaddr(ref_vb2_buf, 0); 298997deb81SDafna Hirschfeld } else { 299997deb81SDafna Hirschfeld ctx->state.ref_frame.buf = NULL; 300997deb81SDafna Hirschfeld } 301997deb81SDafna Hirschfeld } 302b9bbbbfeSDafna Hirschfeld p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0); 303b9bbbbfeSDafna Hirschfeld if (!p_src || !p_dst) { 304256bf813SHans Verkuil v4l2_err(&dev->v4l2_dev, 305256bf813SHans Verkuil "Acquiring kernel pointers to buffers failed\n"); 306256bf813SHans Verkuil return -EFAULT; 307256bf813SHans Verkuil } 308256bf813SHans Verkuil 309256bf813SHans Verkuil if (ctx->is_enc) { 310b9bbbbfeSDafna Hirschfeld struct vicodec_q_data *q_src; 311f902796aSDafna Hirschfeld int comp_sz_or_errcode; 312256bf813SHans Verkuil 313b9bbbbfeSDafna Hirschfeld q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 314b9bbbbfeSDafna Hirschfeld state->info = q_src->info; 315f902796aSDafna Hirschfeld comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst); 316f902796aSDafna Hirschfeld if (comp_sz_or_errcode < 0) 317f902796aSDafna Hirschfeld return comp_sz_or_errcode; 318f902796aSDafna Hirschfeld vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode); 319256bf813SHans Verkuil } else { 3208eead25cSDafna Hirschfeld struct vicodec_q_data *q_dst; 321f863f222SDafna Hirschfeld unsigned int comp_frame_size = ntohl(ctx->state.header.size); 322f863f222SDafna Hirschfeld 3238eead25cSDafna Hirschfeld q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 324f863f222SDafna Hirschfeld if (comp_frame_size > ctx->comp_max_size) 325f863f222SDafna Hirschfeld return -EINVAL; 326b9bbbbfeSDafna Hirschfeld state->info = q_dst->info; 327b9bbbbfeSDafna Hirschfeld ret = v4l2_fwht_decode(state, p_src, p_dst); 328b09d8b25SHans Verkuil if (ret < 0) 329256bf813SHans Verkuil return ret; 330997deb81SDafna Hirschfeld if (!ctx->is_stateless) 33186764b88SDafna Hirschfeld copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); 33286764b88SDafna Hirschfeld 333b9bbbbfeSDafna Hirschfeld vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); 3343abfc314SHans Verkuil if (ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME) 335fbbbb2cdSHans Verkuil dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; 336fbbbb2cdSHans Verkuil else 337fbbbb2cdSHans Verkuil dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; 338256bf813SHans Verkuil } 339997deb81SDafna Hirschfeld return ret; 340256bf813SHans Verkuil } 341256bf813SHans Verkuil 342256bf813SHans Verkuil /* 343256bf813SHans Verkuil * mem2mem callbacks 344256bf813SHans Verkuil */ 345c9d06df6SMauro Carvalho Chehab static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, 346c9d06df6SMauro Carvalho Chehab u8 **pp, u32 sz) 347ddc1b085SDafna Hirschfeld { 348ddc1b085SDafna Hirschfeld static const u8 magic[] = { 349ddc1b085SDafna Hirschfeld 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff 350ddc1b085SDafna Hirschfeld }; 351ddc1b085SDafna Hirschfeld u8 *p = *pp; 352ddc1b085SDafna Hirschfeld u32 state; 353ddc1b085SDafna Hirschfeld u8 *header = (u8 *)&ctx->state.header; 354ddc1b085SDafna Hirschfeld 355ddc1b085SDafna Hirschfeld state = VB2_BUF_STATE_DONE; 356ddc1b085SDafna Hirschfeld 357ddc1b085SDafna Hirschfeld if (!ctx->header_size) { 358ddc1b085SDafna Hirschfeld state = VB2_BUF_STATE_ERROR; 359ddc1b085SDafna Hirschfeld for (; p < *pp + sz; p++) { 360ddc1b085SDafna Hirschfeld u32 copy; 361ddc1b085SDafna Hirschfeld 362ddc1b085SDafna Hirschfeld p = memchr(p, magic[ctx->comp_magic_cnt], 363ddc1b085SDafna Hirschfeld *pp + sz - p); 364ddc1b085SDafna Hirschfeld if (!p) { 365ddc1b085SDafna Hirschfeld ctx->comp_magic_cnt = 0; 366ddc1b085SDafna Hirschfeld p = *pp + sz; 367ddc1b085SDafna Hirschfeld break; 368ddc1b085SDafna Hirschfeld } 369ddc1b085SDafna Hirschfeld copy = sizeof(magic) - ctx->comp_magic_cnt; 370ddc1b085SDafna Hirschfeld if (*pp + sz - p < copy) 371ddc1b085SDafna Hirschfeld copy = *pp + sz - p; 372ddc1b085SDafna Hirschfeld 373ddc1b085SDafna Hirschfeld memcpy(header + ctx->comp_magic_cnt, p, copy); 374ddc1b085SDafna Hirschfeld ctx->comp_magic_cnt += copy; 375ddc1b085SDafna Hirschfeld if (!memcmp(header, magic, ctx->comp_magic_cnt)) { 376ddc1b085SDafna Hirschfeld p += copy; 377ddc1b085SDafna Hirschfeld state = VB2_BUF_STATE_DONE; 378ddc1b085SDafna Hirschfeld break; 379ddc1b085SDafna Hirschfeld } 380ddc1b085SDafna Hirschfeld ctx->comp_magic_cnt = 0; 381ddc1b085SDafna Hirschfeld } 382ddc1b085SDafna Hirschfeld if (ctx->comp_magic_cnt < sizeof(magic)) { 383ddc1b085SDafna Hirschfeld *pp = p; 384ddc1b085SDafna Hirschfeld return state; 385ddc1b085SDafna Hirschfeld } 386ddc1b085SDafna Hirschfeld ctx->header_size = sizeof(magic); 387ddc1b085SDafna Hirschfeld } 388ddc1b085SDafna Hirschfeld 389ddc1b085SDafna Hirschfeld if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { 390ddc1b085SDafna Hirschfeld u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size; 391ddc1b085SDafna Hirschfeld 392ddc1b085SDafna Hirschfeld if (*pp + sz - p < copy) 393ddc1b085SDafna Hirschfeld copy = *pp + sz - p; 394ddc1b085SDafna Hirschfeld 395ddc1b085SDafna Hirschfeld memcpy(header + ctx->header_size, p, copy); 396ddc1b085SDafna Hirschfeld p += copy; 397ddc1b085SDafna Hirschfeld ctx->header_size += copy; 398ddc1b085SDafna Hirschfeld } 399ddc1b085SDafna Hirschfeld *pp = p; 400ddc1b085SDafna Hirschfeld return state; 401ddc1b085SDafna Hirschfeld } 402256bf813SHans Verkuil 403256bf813SHans Verkuil /* device_run() - prepares and starts the device */ 404256bf813SHans Verkuil static void device_run(void *priv) 405256bf813SHans Verkuil { 406256bf813SHans Verkuil struct vicodec_ctx *ctx = priv; 407256bf813SHans Verkuil struct vicodec_dev *dev = ctx->dev; 408256bf813SHans Verkuil struct vb2_v4l2_buffer *src_buf, *dst_buf; 4098eead25cSDafna Hirschfeld struct vicodec_q_data *q_src, *q_dst; 410256bf813SHans Verkuil u32 state; 411997deb81SDafna Hirschfeld struct media_request *src_req; 412997deb81SDafna Hirschfeld 413256bf813SHans Verkuil src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 414256bf813SHans Verkuil dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 415997deb81SDafna Hirschfeld src_req = src_buf->vb2_buf.req_obj.req; 416997deb81SDafna Hirschfeld 417b9bbbbfeSDafna Hirschfeld q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 4188eead25cSDafna Hirschfeld q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 419256bf813SHans Verkuil 420256bf813SHans Verkuil state = VB2_BUF_STATE_DONE; 421256bf813SHans Verkuil if (device_process(ctx, src_buf, dst_buf)) 422256bf813SHans Verkuil state = VB2_BUF_STATE_ERROR; 4238eead25cSDafna Hirschfeld else 4248eead25cSDafna Hirschfeld dst_buf->sequence = q_dst->sequence++; 4258eead25cSDafna Hirschfeld dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; 426fbbbb2cdSHans Verkuil v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); 4278eead25cSDafna Hirschfeld 428256bf813SHans Verkuil spin_lock(ctx->lock); 429d4d137deSNeil Armstrong if (!ctx->comp_has_next_frame && 430d4d137deSNeil Armstrong v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { 431256bf813SHans Verkuil dst_buf->flags |= V4L2_BUF_FLAG_LAST; 432d17589afSHans Verkuil v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); 433d4d137deSNeil Armstrong v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); 434256bf813SHans Verkuil } 435997deb81SDafna Hirschfeld if (ctx->is_enc || ctx->is_stateless) { 436b9bbbbfeSDafna Hirschfeld src_buf->sequence = q_src->sequence++; 437256bf813SHans Verkuil src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 438256bf813SHans Verkuil v4l2_m2m_buf_done(src_buf, state); 439256bf813SHans Verkuil } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) { 440b9bbbbfeSDafna Hirschfeld src_buf->sequence = q_src->sequence++; 441256bf813SHans Verkuil src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 442256bf813SHans Verkuil v4l2_m2m_buf_done(src_buf, state); 443256bf813SHans Verkuil ctx->cur_buf_offset = 0; 444256bf813SHans Verkuil ctx->comp_has_next_frame = false; 445256bf813SHans Verkuil } 446256bf813SHans Verkuil v4l2_m2m_buf_done(dst_buf, state); 447997deb81SDafna Hirschfeld 448256bf813SHans Verkuil ctx->comp_size = 0; 449ddc1b085SDafna Hirschfeld ctx->header_size = 0; 450256bf813SHans Verkuil ctx->comp_magic_cnt = 0; 451256bf813SHans Verkuil ctx->comp_has_frame = false; 452256bf813SHans Verkuil spin_unlock(ctx->lock); 453e5bc0e1dSHans Verkuil if (ctx->is_stateless && src_req) 454e5bc0e1dSHans Verkuil v4l2_ctrl_request_complete(src_req, &ctx->hdl); 455256bf813SHans Verkuil 456256bf813SHans Verkuil if (ctx->is_enc) 457c022a4a9SDafna Hirschfeld v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); 458fde649b4SDafna Hirschfeld else if (ctx->is_stateless) 459fde649b4SDafna Hirschfeld v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev, 460fde649b4SDafna Hirschfeld ctx->fh.m2m_ctx); 461256bf813SHans Verkuil else 462c022a4a9SDafna Hirschfeld v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx); 463256bf813SHans Verkuil } 464256bf813SHans Verkuil 465b9bbbbfeSDafna Hirschfeld static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state) 466256bf813SHans Verkuil { 467256bf813SHans Verkuil struct vb2_v4l2_buffer *src_buf; 468b9bbbbfeSDafna Hirschfeld struct vicodec_q_data *q_src; 469256bf813SHans Verkuil 470b9bbbbfeSDafna Hirschfeld q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 471256bf813SHans Verkuil spin_lock(ctx->lock); 472256bf813SHans Verkuil src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 473b9bbbbfeSDafna Hirschfeld src_buf->sequence = q_src->sequence++; 474256bf813SHans Verkuil v4l2_m2m_buf_done(src_buf, state); 475256bf813SHans Verkuil ctx->cur_buf_offset = 0; 476256bf813SHans Verkuil spin_unlock(ctx->lock); 477256bf813SHans Verkuil } 478256bf813SHans Verkuil 4793b15f68eSDafna Hirschfeld static const struct v4l2_fwht_pixfmt_info * 4803b15f68eSDafna Hirschfeld info_from_header(const struct fwht_cframe_hdr *p_hdr) 4813b15f68eSDafna Hirschfeld { 4823b15f68eSDafna Hirschfeld unsigned int flags = ntohl(p_hdr->flags); 4833abfc314SHans Verkuil unsigned int width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 4843abfc314SHans Verkuil unsigned int height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 4853b15f68eSDafna Hirschfeld unsigned int components_num = 3; 4863b15f68eSDafna Hirschfeld unsigned int pixenc = 0; 4873b15f68eSDafna Hirschfeld unsigned int version = ntohl(p_hdr->version); 4883b15f68eSDafna Hirschfeld 48975e3e5b8SDafna Hirschfeld if (version >= 2) { 4903abfc314SHans Verkuil components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> 4913abfc314SHans Verkuil V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); 4923abfc314SHans Verkuil pixenc = (flags & V4L2_FWHT_FL_PIXENC_MSK); 4933b15f68eSDafna Hirschfeld } 49450e4c5e1SDafna Hirschfeld return v4l2_fwht_find_nth_fmt(width_div, height_div, 4953b15f68eSDafna Hirschfeld components_num, pixenc, 0); 4963b15f68eSDafna Hirschfeld } 4973b15f68eSDafna Hirschfeld 4983b15f68eSDafna Hirschfeld static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) 4993b15f68eSDafna Hirschfeld { 5003b15f68eSDafna Hirschfeld const struct v4l2_fwht_pixfmt_info *info; 5013b15f68eSDafna Hirschfeld unsigned int w = ntohl(p_hdr->width); 5023b15f68eSDafna Hirschfeld unsigned int h = ntohl(p_hdr->height); 5033b15f68eSDafna Hirschfeld unsigned int version = ntohl(p_hdr->version); 5043b15f68eSDafna Hirschfeld unsigned int flags = ntohl(p_hdr->flags); 5053b15f68eSDafna Hirschfeld 5063b15f68eSDafna Hirschfeld if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) 5073b15f68eSDafna Hirschfeld return false; 5083b15f68eSDafna Hirschfeld 50992dc64d4SDafna Hirschfeld if (!validate_by_version(flags, version)) 5103b15f68eSDafna Hirschfeld return false; 5113b15f68eSDafna Hirschfeld 5123b15f68eSDafna Hirschfeld info = info_from_header(p_hdr); 5133b15f68eSDafna Hirschfeld if (!info) 5143b15f68eSDafna Hirschfeld return false; 5153b15f68eSDafna Hirschfeld return true; 5163b15f68eSDafna Hirschfeld } 5173b15f68eSDafna Hirschfeld 5183b15f68eSDafna Hirschfeld static void update_capture_data_from_header(struct vicodec_ctx *ctx) 5193b15f68eSDafna Hirschfeld { 5203b15f68eSDafna Hirschfeld struct vicodec_q_data *q_dst = get_q_data(ctx, 5213b15f68eSDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 5223b15f68eSDafna Hirschfeld const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; 5233b15f68eSDafna Hirschfeld const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr); 5243b15f68eSDafna Hirschfeld unsigned int flags = ntohl(p_hdr->flags); 5253abfc314SHans Verkuil unsigned int hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 5263abfc314SHans Verkuil unsigned int hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 5273b15f68eSDafna Hirschfeld 528997deb81SDafna Hirschfeld /* 529997deb81SDafna Hirschfeld * This function should not be used by a stateless codec since 530997deb81SDafna Hirschfeld * it changes values in q_data that are not request specific 531997deb81SDafna Hirschfeld */ 532997deb81SDafna Hirschfeld WARN_ON(ctx->is_stateless); 533997deb81SDafna Hirschfeld 5343b15f68eSDafna Hirschfeld q_dst->info = info; 5353b15f68eSDafna Hirschfeld q_dst->visible_width = ntohl(p_hdr->width); 5363b15f68eSDafna Hirschfeld q_dst->visible_height = ntohl(p_hdr->height); 5373b15f68eSDafna Hirschfeld q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div); 5383b15f68eSDafna Hirschfeld q_dst->coded_height = vic_round_dim(q_dst->visible_height, 5393b15f68eSDafna Hirschfeld hdr_height_div); 5403b15f68eSDafna Hirschfeld 5413b15f68eSDafna Hirschfeld q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height * 5423b15f68eSDafna Hirschfeld q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div; 5433b15f68eSDafna Hirschfeld ctx->state.colorspace = ntohl(p_hdr->colorspace); 5443b15f68eSDafna Hirschfeld 5453b15f68eSDafna Hirschfeld ctx->state.xfer_func = ntohl(p_hdr->xfer_func); 5463b15f68eSDafna Hirschfeld ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); 5473b15f68eSDafna Hirschfeld ctx->state.quantization = ntohl(p_hdr->quantization); 5483b15f68eSDafna Hirschfeld } 5493b15f68eSDafna Hirschfeld 5503b15f68eSDafna Hirschfeld static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf, 5513b15f68eSDafna Hirschfeld const struct vb2_v4l2_buffer *src_buf, 5523b15f68eSDafna Hirschfeld struct vicodec_ctx *ctx) 5533b15f68eSDafna Hirschfeld { 5543b15f68eSDafna Hirschfeld struct vicodec_q_data *q_dst = get_q_data(ctx, 5553b15f68eSDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 5563b15f68eSDafna Hirschfeld 5573b15f68eSDafna Hirschfeld vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); 5583b15f68eSDafna Hirschfeld dst_buf->sequence = q_dst->sequence++; 5593b15f68eSDafna Hirschfeld 560a4d3d612SEzequiel Garcia v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); 5613b15f68eSDafna Hirschfeld dst_buf->flags |= V4L2_BUF_FLAG_LAST; 5623b15f68eSDafna Hirschfeld v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); 5633b15f68eSDafna Hirschfeld } 5643b15f68eSDafna Hirschfeld 565256bf813SHans Verkuil static int job_ready(void *priv) 566256bf813SHans Verkuil { 567256bf813SHans Verkuil static const u8 magic[] = { 568256bf813SHans Verkuil 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff 569256bf813SHans Verkuil }; 570256bf813SHans Verkuil struct vicodec_ctx *ctx = priv; 571256bf813SHans Verkuil struct vb2_v4l2_buffer *src_buf; 572b9bbbbfeSDafna Hirschfeld u8 *p_src; 573256bf813SHans Verkuil u8 *p; 574256bf813SHans Verkuil u32 sz; 575256bf813SHans Verkuil u32 state; 5763b15f68eSDafna Hirschfeld struct vicodec_q_data *q_dst = get_q_data(ctx, 5773b15f68eSDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 5783b15f68eSDafna Hirschfeld unsigned int flags; 5793b15f68eSDafna Hirschfeld unsigned int hdr_width_div; 5803b15f68eSDafna Hirschfeld unsigned int hdr_height_div; 5813b15f68eSDafna Hirschfeld unsigned int max_to_copy; 5823b15f68eSDafna Hirschfeld unsigned int comp_frame_size; 583256bf813SHans Verkuil 5843b15f68eSDafna Hirschfeld if (ctx->source_changed) 5853b15f68eSDafna Hirschfeld return 0; 586997deb81SDafna Hirschfeld if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) 587256bf813SHans Verkuil return 1; 588256bf813SHans Verkuil 589256bf813SHans Verkuil restart: 590256bf813SHans Verkuil ctx->comp_has_next_frame = false; 591256bf813SHans Verkuil src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 592256bf813SHans Verkuil if (!src_buf) 593256bf813SHans Verkuil return 0; 594b9bbbbfeSDafna Hirschfeld p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 595256bf813SHans Verkuil sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0); 596b9bbbbfeSDafna Hirschfeld p = p_src + ctx->cur_buf_offset; 597256bf813SHans Verkuil 598256bf813SHans Verkuil state = VB2_BUF_STATE_DONE; 599256bf813SHans Verkuil 600ddc1b085SDafna Hirschfeld if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { 601ddc1b085SDafna Hirschfeld state = get_next_header(ctx, &p, p_src + sz - p); 602ddc1b085SDafna Hirschfeld if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { 603d4d137deSNeil Armstrong if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, 604d4d137deSNeil Armstrong src_buf)) 605d17589afSHans Verkuil return 1; 606b9bbbbfeSDafna Hirschfeld job_remove_src_buf(ctx, state); 607256bf813SHans Verkuil goto restart; 608256bf813SHans Verkuil } 609256bf813SHans Verkuil } 6103b15f68eSDafna Hirschfeld 6113b15f68eSDafna Hirschfeld comp_frame_size = ntohl(ctx->state.header.size); 6123b15f68eSDafna Hirschfeld 6133b15f68eSDafna Hirschfeld /* 6143b15f68eSDafna Hirschfeld * The current scanned frame might be the first frame of a new 6153b15f68eSDafna Hirschfeld * resolution so its size might be larger than ctx->comp_max_size. 6163b15f68eSDafna Hirschfeld * In that case it is copied up to the current buffer capacity and 6173b15f68eSDafna Hirschfeld * the copy will continue after allocating new large enough buffer 6183b15f68eSDafna Hirschfeld * when restreaming 6193b15f68eSDafna Hirschfeld */ 6203b15f68eSDafna Hirschfeld max_to_copy = min(comp_frame_size, ctx->comp_max_size); 6213b15f68eSDafna Hirschfeld 6223b15f68eSDafna Hirschfeld if (ctx->comp_size < max_to_copy) { 6233b15f68eSDafna Hirschfeld u32 copy = max_to_copy - ctx->comp_size; 624256bf813SHans Verkuil 625b9bbbbfeSDafna Hirschfeld if (copy > p_src + sz - p) 626b9bbbbfeSDafna Hirschfeld copy = p_src + sz - p; 627b9bbbbfeSDafna Hirschfeld 628cd12b401SHans Verkuil memcpy(ctx->state.compressed_frame + ctx->comp_size, 629256bf813SHans Verkuil p, copy); 630256bf813SHans Verkuil p += copy; 631256bf813SHans Verkuil ctx->comp_size += copy; 6323b15f68eSDafna Hirschfeld if (ctx->comp_size < max_to_copy) { 633d4d137deSNeil Armstrong if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, 634d4d137deSNeil Armstrong src_buf)) 635d17589afSHans Verkuil return 1; 636b9bbbbfeSDafna Hirschfeld job_remove_src_buf(ctx, state); 637256bf813SHans Verkuil goto restart; 638256bf813SHans Verkuil } 639256bf813SHans Verkuil } 640b9bbbbfeSDafna Hirschfeld ctx->cur_buf_offset = p - p_src; 6413b15f68eSDafna Hirschfeld if (ctx->comp_size == comp_frame_size) 642256bf813SHans Verkuil ctx->comp_has_frame = true; 643256bf813SHans Verkuil ctx->comp_has_next_frame = false; 6443b15f68eSDafna Hirschfeld if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >= 6453b15f68eSDafna Hirschfeld sizeof(struct fwht_cframe_hdr)) { 64621abebf0SHans Verkuil struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p; 647256bf813SHans Verkuil u32 frame_size = ntohl(p_hdr->size); 648256bf813SHans Verkuil u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr); 649256bf813SHans Verkuil 650256bf813SHans Verkuil if (!memcmp(p, magic, sizeof(magic))) 651256bf813SHans Verkuil ctx->comp_has_next_frame = remaining >= frame_size; 652256bf813SHans Verkuil } 6533b15f68eSDafna Hirschfeld /* 6543b15f68eSDafna Hirschfeld * if the header is invalid the device_run will just drop the frame 6553b15f68eSDafna Hirschfeld * with an error 6563b15f68eSDafna Hirschfeld */ 6573b15f68eSDafna Hirschfeld if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) 6583b15f68eSDafna Hirschfeld return 1; 6593b15f68eSDafna Hirschfeld flags = ntohl(ctx->state.header.flags); 6603abfc314SHans Verkuil hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 6613abfc314SHans Verkuil hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 6623b15f68eSDafna Hirschfeld 6633b15f68eSDafna Hirschfeld if (ntohl(ctx->state.header.width) != q_dst->visible_width || 6643b15f68eSDafna Hirschfeld ntohl(ctx->state.header.height) != q_dst->visible_height || 6653b15f68eSDafna Hirschfeld !q_dst->info || 6663b15f68eSDafna Hirschfeld hdr_width_div != q_dst->info->width_div || 6673b15f68eSDafna Hirschfeld hdr_height_div != q_dst->info->height_div) { 6683b15f68eSDafna Hirschfeld static const struct v4l2_event rs_event = { 6693b15f68eSDafna Hirschfeld .type = V4L2_EVENT_SOURCE_CHANGE, 6703b15f68eSDafna Hirschfeld .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 6713b15f68eSDafna Hirschfeld }; 6723b15f68eSDafna Hirschfeld 6733b15f68eSDafna Hirschfeld struct vb2_v4l2_buffer *dst_buf = 6743b15f68eSDafna Hirschfeld v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 6753b15f68eSDafna Hirschfeld 6763b15f68eSDafna Hirschfeld update_capture_data_from_header(ctx); 6773b15f68eSDafna Hirschfeld v4l2_event_queue_fh(&ctx->fh, &rs_event); 6783b15f68eSDafna Hirschfeld set_last_buffer(dst_buf, src_buf, ctx); 6793b15f68eSDafna Hirschfeld ctx->source_changed = true; 6803b15f68eSDafna Hirschfeld return 0; 6813b15f68eSDafna Hirschfeld } 682256bf813SHans Verkuil return 1; 683256bf813SHans Verkuil } 684256bf813SHans Verkuil 685256bf813SHans Verkuil /* 686256bf813SHans Verkuil * video ioctls 687256bf813SHans Verkuil */ 688256bf813SHans Verkuil 689cd12b401SHans Verkuil static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt) 690256bf813SHans Verkuil { 691cd12b401SHans Verkuil const struct v4l2_fwht_pixfmt_info *info = 692cd12b401SHans Verkuil v4l2_fwht_find_pixfmt(fmt); 693256bf813SHans Verkuil 694cd12b401SHans Verkuil if (!info) 695cd12b401SHans Verkuil info = v4l2_fwht_get_pixfmt(0); 696cd12b401SHans Verkuil return info; 697256bf813SHans Verkuil } 698256bf813SHans Verkuil 699256bf813SHans Verkuil static int vidioc_querycap(struct file *file, void *priv, 700256bf813SHans Verkuil struct v4l2_capability *cap) 701256bf813SHans Verkuil { 70285709cbfSMauro Carvalho Chehab strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver)); 70385709cbfSMauro Carvalho Chehab strscpy(cap->card, VICODEC_NAME, sizeof(cap->card)); 704256bf813SHans Verkuil snprintf(cap->bus_info, sizeof(cap->bus_info), 705256bf813SHans Verkuil "platform:%s", VICODEC_NAME); 706256bf813SHans Verkuil return 0; 707256bf813SHans Verkuil } 708256bf813SHans Verkuil 7095fbd0729SDafna Hirschfeld static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, 7105fbd0729SDafna Hirschfeld bool is_out) 711256bf813SHans Verkuil { 7125fbd0729SDafna Hirschfeld bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out); 713256bf813SHans Verkuil 714256bf813SHans Verkuil if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar) 715256bf813SHans Verkuil return -EINVAL; 716256bf813SHans Verkuil if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar) 717256bf813SHans Verkuil return -EINVAL; 718256bf813SHans Verkuil 719cd12b401SHans Verkuil if (is_uncomp) { 720cd12b401SHans Verkuil const struct v4l2_fwht_pixfmt_info *info = 7215fbd0729SDafna Hirschfeld get_q_data(ctx, f->type)->info; 722cd12b401SHans Verkuil 723d17589afSHans Verkuil if (ctx->is_enc || 724d17589afSHans Verkuil !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) 7255fbd0729SDafna Hirschfeld info = v4l2_fwht_get_pixfmt(f->index); 7265fbd0729SDafna Hirschfeld else 72750e4c5e1SDafna Hirschfeld info = v4l2_fwht_find_nth_fmt(info->width_div, 7285fbd0729SDafna Hirschfeld info->height_div, 7295fbd0729SDafna Hirschfeld info->components_num, 7305fbd0729SDafna Hirschfeld info->pixenc, 7315fbd0729SDafna Hirschfeld f->index); 732cd12b401SHans Verkuil if (!info) 733cd12b401SHans Verkuil return -EINVAL; 734cd12b401SHans Verkuil f->pixelformat = info->id; 735cd12b401SHans Verkuil } else { 736cd12b401SHans Verkuil if (f->index) 737cd12b401SHans Verkuil return -EINVAL; 73835e2e8b5SDafna Hirschfeld f->pixelformat = ctx->is_stateless ? 73935e2e8b5SDafna Hirschfeld V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; 740b867d9ceSMaxime Jourdan if (!ctx->is_enc && !ctx->is_stateless) 741b867d9ceSMaxime Jourdan f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | 742b867d9ceSMaxime Jourdan V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM; 743cd12b401SHans Verkuil } 744256bf813SHans Verkuil return 0; 745256bf813SHans Verkuil } 746256bf813SHans Verkuil 747256bf813SHans Verkuil static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 748256bf813SHans Verkuil struct v4l2_fmtdesc *f) 749256bf813SHans Verkuil { 750256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 751256bf813SHans Verkuil 7525fbd0729SDafna Hirschfeld return enum_fmt(f, ctx, false); 753256bf813SHans Verkuil } 754256bf813SHans Verkuil 755256bf813SHans Verkuil static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, 756256bf813SHans Verkuil struct v4l2_fmtdesc *f) 757256bf813SHans Verkuil { 758256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 759256bf813SHans Verkuil 7605fbd0729SDafna Hirschfeld return enum_fmt(f, ctx, true); 761256bf813SHans Verkuil } 762256bf813SHans Verkuil 763256bf813SHans Verkuil static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 764256bf813SHans Verkuil { 765256bf813SHans Verkuil struct vb2_queue *vq; 766256bf813SHans Verkuil struct vicodec_q_data *q_data; 767256bf813SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 768256bf813SHans Verkuil struct v4l2_pix_format *pix; 769cd12b401SHans Verkuil const struct v4l2_fwht_pixfmt_info *info; 770256bf813SHans Verkuil 771256bf813SHans Verkuil vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 772256bf813SHans Verkuil if (!vq) 773256bf813SHans Verkuil return -EINVAL; 774256bf813SHans Verkuil 775256bf813SHans Verkuil q_data = get_q_data(ctx, f->type); 77629a7a5e9SHans Verkuil info = q_data->info; 777256bf813SHans Verkuil 778256bf813SHans Verkuil switch (f->type) { 779256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE: 780256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 781256bf813SHans Verkuil if (multiplanar) 782256bf813SHans Verkuil return -EINVAL; 783256bf813SHans Verkuil pix = &f->fmt.pix; 7849e812549SDafna Hirschfeld pix->width = q_data->coded_width; 7859e812549SDafna Hirschfeld pix->height = q_data->coded_height; 786256bf813SHans Verkuil pix->field = V4L2_FIELD_NONE; 78729a7a5e9SHans Verkuil pix->pixelformat = info->id; 7889e812549SDafna Hirschfeld pix->bytesperline = q_data->coded_width * 7899e812549SDafna Hirschfeld info->bytesperline_mult; 790256bf813SHans Verkuil pix->sizeimage = q_data->sizeimage; 791cd12b401SHans Verkuil pix->colorspace = ctx->state.colorspace; 792cd12b401SHans Verkuil pix->xfer_func = ctx->state.xfer_func; 793cd12b401SHans Verkuil pix->ycbcr_enc = ctx->state.ycbcr_enc; 794cd12b401SHans Verkuil pix->quantization = ctx->state.quantization; 795256bf813SHans Verkuil break; 796256bf813SHans Verkuil 797256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 798256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 799256bf813SHans Verkuil if (!multiplanar) 800256bf813SHans Verkuil return -EINVAL; 801256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 8029e812549SDafna Hirschfeld pix_mp->width = q_data->coded_width; 8039e812549SDafna Hirschfeld pix_mp->height = q_data->coded_height; 804256bf813SHans Verkuil pix_mp->field = V4L2_FIELD_NONE; 80529a7a5e9SHans Verkuil pix_mp->pixelformat = info->id; 806256bf813SHans Verkuil pix_mp->num_planes = 1; 80729a7a5e9SHans Verkuil pix_mp->plane_fmt[0].bytesperline = 8089e812549SDafna Hirschfeld q_data->coded_width * info->bytesperline_mult; 809256bf813SHans Verkuil pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage; 810cd12b401SHans Verkuil pix_mp->colorspace = ctx->state.colorspace; 811cd12b401SHans Verkuil pix_mp->xfer_func = ctx->state.xfer_func; 812cd12b401SHans Verkuil pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; 813cd12b401SHans Verkuil pix_mp->quantization = ctx->state.quantization; 814256bf813SHans Verkuil memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); 815256bf813SHans Verkuil memset(pix_mp->plane_fmt[0].reserved, 0, 816256bf813SHans Verkuil sizeof(pix_mp->plane_fmt[0].reserved)); 817256bf813SHans Verkuil break; 818256bf813SHans Verkuil default: 819256bf813SHans Verkuil return -EINVAL; 820256bf813SHans Verkuil } 821256bf813SHans Verkuil return 0; 822256bf813SHans Verkuil } 823256bf813SHans Verkuil 824256bf813SHans Verkuil static int vidioc_g_fmt_vid_out(struct file *file, void *priv, 825256bf813SHans Verkuil struct v4l2_format *f) 826256bf813SHans Verkuil { 827256bf813SHans Verkuil return vidioc_g_fmt(file2ctx(file), f); 828256bf813SHans Verkuil } 829256bf813SHans Verkuil 830256bf813SHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 831256bf813SHans Verkuil struct v4l2_format *f) 832256bf813SHans Verkuil { 833256bf813SHans Verkuil return vidioc_g_fmt(file2ctx(file), f); 834256bf813SHans Verkuil } 835256bf813SHans Verkuil 836256bf813SHans Verkuil static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 837256bf813SHans Verkuil { 838256bf813SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 839256bf813SHans Verkuil struct v4l2_pix_format *pix; 84029a7a5e9SHans Verkuil struct v4l2_plane_pix_format *plane; 84135e2e8b5SDafna Hirschfeld const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? 84235e2e8b5SDafna Hirschfeld &pixfmt_stateless_fwht : &pixfmt_fwht; 843256bf813SHans Verkuil 844256bf813SHans Verkuil switch (f->type) { 845256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE: 846256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 847256bf813SHans Verkuil pix = &f->fmt.pix; 84835e2e8b5SDafna Hirschfeld if (pix->pixelformat != V4L2_PIX_FMT_FWHT && 84935e2e8b5SDafna Hirschfeld pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) 85029a7a5e9SHans Verkuil info = find_fmt(pix->pixelformat); 8519e812549SDafna Hirschfeld 8529e812549SDafna Hirschfeld pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); 8539e812549SDafna Hirschfeld pix->width = vic_round_dim(pix->width, info->width_div); 8549e812549SDafna Hirschfeld 8559e812549SDafna Hirschfeld pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); 8569e812549SDafna Hirschfeld pix->height = vic_round_dim(pix->height, info->height_div); 8579e812549SDafna Hirschfeld 858256bf813SHans Verkuil pix->field = V4L2_FIELD_NONE; 85929a7a5e9SHans Verkuil pix->bytesperline = 86029a7a5e9SHans Verkuil pix->width * info->bytesperline_mult; 86129a7a5e9SHans Verkuil pix->sizeimage = pix->width * pix->height * 86229a7a5e9SHans Verkuil info->sizeimage_mult / info->sizeimage_div; 86329a7a5e9SHans Verkuil if (pix->pixelformat == V4L2_PIX_FMT_FWHT) 86421abebf0SHans Verkuil pix->sizeimage += sizeof(struct fwht_cframe_hdr); 865256bf813SHans Verkuil break; 866256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 867256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 868256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 86929a7a5e9SHans Verkuil plane = pix_mp->plane_fmt; 87035e2e8b5SDafna Hirschfeld if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT && 87135e2e8b5SDafna Hirschfeld pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) 87229a7a5e9SHans Verkuil info = find_fmt(pix_mp->pixelformat); 87329a7a5e9SHans Verkuil pix_mp->num_planes = 1; 8749e812549SDafna Hirschfeld 8759e812549SDafna Hirschfeld pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH); 8769e812549SDafna Hirschfeld pix_mp->width = vic_round_dim(pix_mp->width, info->width_div); 8779e812549SDafna Hirschfeld 8789e812549SDafna Hirschfeld pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT); 8799e812549SDafna Hirschfeld pix_mp->height = vic_round_dim(pix_mp->height, 8809e812549SDafna Hirschfeld info->height_div); 8819e812549SDafna Hirschfeld 882256bf813SHans Verkuil pix_mp->field = V4L2_FIELD_NONE; 88329a7a5e9SHans Verkuil plane->bytesperline = 88429a7a5e9SHans Verkuil pix_mp->width * info->bytesperline_mult; 88529a7a5e9SHans Verkuil plane->sizeimage = pix_mp->width * pix_mp->height * 88629a7a5e9SHans Verkuil info->sizeimage_mult / info->sizeimage_div; 88729a7a5e9SHans Verkuil if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) 88821abebf0SHans Verkuil plane->sizeimage += sizeof(struct fwht_cframe_hdr); 889256bf813SHans Verkuil memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); 89029a7a5e9SHans Verkuil memset(plane->reserved, 0, sizeof(plane->reserved)); 891256bf813SHans Verkuil break; 892256bf813SHans Verkuil default: 893256bf813SHans Verkuil return -EINVAL; 894256bf813SHans Verkuil } 895256bf813SHans Verkuil 896256bf813SHans Verkuil return 0; 897256bf813SHans Verkuil } 898256bf813SHans Verkuil 899256bf813SHans Verkuil static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 900256bf813SHans Verkuil struct v4l2_format *f) 901256bf813SHans Verkuil { 902256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 903256bf813SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 904256bf813SHans Verkuil struct v4l2_pix_format *pix; 905256bf813SHans Verkuil 906256bf813SHans Verkuil switch (f->type) { 907256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE: 908256bf813SHans Verkuil if (multiplanar) 909256bf813SHans Verkuil return -EINVAL; 910256bf813SHans Verkuil pix = &f->fmt.pix; 911256bf813SHans Verkuil pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : 91229a7a5e9SHans Verkuil find_fmt(f->fmt.pix.pixelformat)->id; 913cd12b401SHans Verkuil pix->colorspace = ctx->state.colorspace; 914cd12b401SHans Verkuil pix->xfer_func = ctx->state.xfer_func; 915cd12b401SHans Verkuil pix->ycbcr_enc = ctx->state.ycbcr_enc; 916cd12b401SHans Verkuil pix->quantization = ctx->state.quantization; 917256bf813SHans Verkuil break; 918256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 919256bf813SHans Verkuil if (!multiplanar) 920256bf813SHans Verkuil return -EINVAL; 921256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 922256bf813SHans Verkuil pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : 92329a7a5e9SHans Verkuil find_fmt(pix_mp->pixelformat)->id; 924cd12b401SHans Verkuil pix_mp->colorspace = ctx->state.colorspace; 925cd12b401SHans Verkuil pix_mp->xfer_func = ctx->state.xfer_func; 926cd12b401SHans Verkuil pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; 927cd12b401SHans Verkuil pix_mp->quantization = ctx->state.quantization; 928256bf813SHans Verkuil break; 929256bf813SHans Verkuil default: 930256bf813SHans Verkuil return -EINVAL; 931256bf813SHans Verkuil } 932256bf813SHans Verkuil 933256bf813SHans Verkuil return vidioc_try_fmt(ctx, f); 934256bf813SHans Verkuil } 935256bf813SHans Verkuil 936256bf813SHans Verkuil static int vidioc_try_fmt_vid_out(struct file *file, void *priv, 937256bf813SHans Verkuil struct v4l2_format *f) 938256bf813SHans Verkuil { 939256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 940256bf813SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 941256bf813SHans Verkuil struct v4l2_pix_format *pix; 942256bf813SHans Verkuil 943256bf813SHans Verkuil switch (f->type) { 944256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 945256bf813SHans Verkuil if (multiplanar) 946256bf813SHans Verkuil return -EINVAL; 947256bf813SHans Verkuil pix = &f->fmt.pix; 94835e2e8b5SDafna Hirschfeld if (ctx->is_enc) 94935e2e8b5SDafna Hirschfeld pix->pixelformat = find_fmt(pix->pixelformat)->id; 95035e2e8b5SDafna Hirschfeld else if (ctx->is_stateless) 95135e2e8b5SDafna Hirschfeld pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; 95235e2e8b5SDafna Hirschfeld else 95335e2e8b5SDafna Hirschfeld pix->pixelformat = V4L2_PIX_FMT_FWHT; 954256bf813SHans Verkuil if (!pix->colorspace) 955256bf813SHans Verkuil pix->colorspace = V4L2_COLORSPACE_REC709; 956256bf813SHans Verkuil break; 957256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 958256bf813SHans Verkuil if (!multiplanar) 959256bf813SHans Verkuil return -EINVAL; 960256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 96135e2e8b5SDafna Hirschfeld if (ctx->is_enc) 96235e2e8b5SDafna Hirschfeld pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id; 96335e2e8b5SDafna Hirschfeld else if (ctx->is_stateless) 96435e2e8b5SDafna Hirschfeld pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; 96535e2e8b5SDafna Hirschfeld else 96635e2e8b5SDafna Hirschfeld pix_mp->pixelformat = V4L2_PIX_FMT_FWHT; 967256bf813SHans Verkuil if (!pix_mp->colorspace) 968256bf813SHans Verkuil pix_mp->colorspace = V4L2_COLORSPACE_REC709; 969256bf813SHans Verkuil break; 970256bf813SHans Verkuil default: 971256bf813SHans Verkuil return -EINVAL; 972256bf813SHans Verkuil } 973256bf813SHans Verkuil 974256bf813SHans Verkuil return vidioc_try_fmt(ctx, f); 975256bf813SHans Verkuil } 976256bf813SHans Verkuil 977256bf813SHans Verkuil static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 978256bf813SHans Verkuil { 979256bf813SHans Verkuil struct vicodec_q_data *q_data; 980256bf813SHans Verkuil struct vb2_queue *vq; 981256bf813SHans Verkuil bool fmt_changed = true; 982256bf813SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 983256bf813SHans Verkuil struct v4l2_pix_format *pix; 984256bf813SHans Verkuil 985256bf813SHans Verkuil vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 986256bf813SHans Verkuil if (!vq) 987256bf813SHans Verkuil return -EINVAL; 988256bf813SHans Verkuil 989256bf813SHans Verkuil q_data = get_q_data(ctx, f->type); 990256bf813SHans Verkuil if (!q_data) 991256bf813SHans Verkuil return -EINVAL; 992256bf813SHans Verkuil 993256bf813SHans Verkuil switch (f->type) { 994256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE: 995256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 996256bf813SHans Verkuil pix = &f->fmt.pix; 997256bf813SHans Verkuil if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) 998256bf813SHans Verkuil fmt_changed = 9993b15f68eSDafna Hirschfeld !q_data->info || 100029a7a5e9SHans Verkuil q_data->info->id != pix->pixelformat || 10019e812549SDafna Hirschfeld q_data->coded_width != pix->width || 10029e812549SDafna Hirschfeld q_data->coded_height != pix->height; 1003256bf813SHans Verkuil 1004256bf813SHans Verkuil if (vb2_is_busy(vq) && fmt_changed) 1005256bf813SHans Verkuil return -EBUSY; 1006256bf813SHans Verkuil 100729a7a5e9SHans Verkuil if (pix->pixelformat == V4L2_PIX_FMT_FWHT) 100829a7a5e9SHans Verkuil q_data->info = &pixfmt_fwht; 100935e2e8b5SDafna Hirschfeld else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) 101035e2e8b5SDafna Hirschfeld q_data->info = &pixfmt_stateless_fwht; 101129a7a5e9SHans Verkuil else 101229a7a5e9SHans Verkuil q_data->info = find_fmt(pix->pixelformat); 10139e812549SDafna Hirschfeld q_data->coded_width = pix->width; 10149e812549SDafna Hirschfeld q_data->coded_height = pix->height; 1015256bf813SHans Verkuil q_data->sizeimage = pix->sizeimage; 1016256bf813SHans Verkuil break; 1017256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 1018256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 1019256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 1020256bf813SHans Verkuil if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) 1021256bf813SHans Verkuil fmt_changed = 10223b15f68eSDafna Hirschfeld !q_data->info || 102329a7a5e9SHans Verkuil q_data->info->id != pix_mp->pixelformat || 10249e812549SDafna Hirschfeld q_data->coded_width != pix_mp->width || 10259e812549SDafna Hirschfeld q_data->coded_height != pix_mp->height; 1026256bf813SHans Verkuil 1027256bf813SHans Verkuil if (vb2_is_busy(vq) && fmt_changed) 1028256bf813SHans Verkuil return -EBUSY; 1029256bf813SHans Verkuil 103029a7a5e9SHans Verkuil if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) 103129a7a5e9SHans Verkuil q_data->info = &pixfmt_fwht; 103235e2e8b5SDafna Hirschfeld else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) 103335e2e8b5SDafna Hirschfeld q_data->info = &pixfmt_stateless_fwht; 103429a7a5e9SHans Verkuil else 103529a7a5e9SHans Verkuil q_data->info = find_fmt(pix_mp->pixelformat); 10369e812549SDafna Hirschfeld q_data->coded_width = pix_mp->width; 10379e812549SDafna Hirschfeld q_data->coded_height = pix_mp->height; 1038256bf813SHans Verkuil q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage; 1039256bf813SHans Verkuil break; 1040256bf813SHans Verkuil default: 1041256bf813SHans Verkuil return -EINVAL; 1042256bf813SHans Verkuil } 1043256bf813SHans Verkuil 1044256bf813SHans Verkuil dprintk(ctx->dev, 1045efec9c81SHans Verkuil "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n", 10469e812549SDafna Hirschfeld f->type, q_data->coded_width, q_data->coded_height, 10479e812549SDafna Hirschfeld q_data->info->id); 1048256bf813SHans Verkuil 1049256bf813SHans Verkuil return 0; 1050256bf813SHans Verkuil } 1051256bf813SHans Verkuil 1052256bf813SHans Verkuil static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 1053256bf813SHans Verkuil struct v4l2_format *f) 1054256bf813SHans Verkuil { 1055256bf813SHans Verkuil int ret; 1056256bf813SHans Verkuil 1057256bf813SHans Verkuil ret = vidioc_try_fmt_vid_cap(file, priv, f); 1058256bf813SHans Verkuil if (ret) 1059256bf813SHans Verkuil return ret; 1060256bf813SHans Verkuil 1061256bf813SHans Verkuil return vidioc_s_fmt(file2ctx(file), f); 1062256bf813SHans Verkuil } 1063256bf813SHans Verkuil 1064256bf813SHans Verkuil static int vidioc_s_fmt_vid_out(struct file *file, void *priv, 1065256bf813SHans Verkuil struct v4l2_format *f) 1066256bf813SHans Verkuil { 1067256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 1068efec9c81SHans Verkuil struct vicodec_q_data *q_data; 1069efec9c81SHans Verkuil struct vicodec_q_data *q_data_cap; 1070256bf813SHans Verkuil struct v4l2_pix_format *pix; 1071efec9c81SHans Verkuil struct v4l2_pix_format_mplane *pix_mp; 1072efec9c81SHans Verkuil u32 coded_w = 0, coded_h = 0; 1073efec9c81SHans Verkuil unsigned int size = 0; 1074256bf813SHans Verkuil int ret; 1075256bf813SHans Verkuil 1076efec9c81SHans Verkuil q_data = get_q_data(ctx, f->type); 1077efec9c81SHans Verkuil q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 1078efec9c81SHans Verkuil 1079256bf813SHans Verkuil ret = vidioc_try_fmt_vid_out(file, priv, f); 1080256bf813SHans Verkuil if (ret) 1081256bf813SHans Verkuil return ret; 1082256bf813SHans Verkuil 1083efec9c81SHans Verkuil if (ctx->is_enc) { 1084efec9c81SHans Verkuil struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 1085efec9c81SHans Verkuil struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 1086efec9c81SHans Verkuil V4L2_BUF_TYPE_VIDEO_CAPTURE); 1087efec9c81SHans Verkuil const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? 1088efec9c81SHans Verkuil &pixfmt_stateless_fwht : &pixfmt_fwht; 1089efec9c81SHans Verkuil 1090efec9c81SHans Verkuil if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 1091efec9c81SHans Verkuil coded_w = f->fmt.pix.width; 1092efec9c81SHans Verkuil coded_h = f->fmt.pix.height; 1093efec9c81SHans Verkuil } else { 1094efec9c81SHans Verkuil coded_w = f->fmt.pix_mp.width; 1095efec9c81SHans Verkuil coded_h = f->fmt.pix_mp.height; 1096efec9c81SHans Verkuil } 1097efec9c81SHans Verkuil if (vb2_is_busy(vq) && (coded_w != q_data->coded_width || 1098efec9c81SHans Verkuil coded_h != q_data->coded_height)) 1099efec9c81SHans Verkuil return -EBUSY; 1100efec9c81SHans Verkuil size = coded_w * coded_h * 1101efec9c81SHans Verkuil info->sizeimage_mult / info->sizeimage_div; 1102efec9c81SHans Verkuil if (!ctx->is_stateless) 1103efec9c81SHans Verkuil size += sizeof(struct fwht_cframe_hdr); 1104efec9c81SHans Verkuil 1105efec9c81SHans Verkuil if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage) 1106efec9c81SHans Verkuil return -EBUSY; 1107efec9c81SHans Verkuil } 1108efec9c81SHans Verkuil 1109256bf813SHans Verkuil ret = vidioc_s_fmt(file2ctx(file), f); 1110256bf813SHans Verkuil if (!ret) { 1111efec9c81SHans Verkuil if (ctx->is_enc) { 1112efec9c81SHans Verkuil q_data->visible_width = coded_w; 1113efec9c81SHans Verkuil q_data->visible_height = coded_h; 1114efec9c81SHans Verkuil q_data_cap->coded_width = coded_w; 1115efec9c81SHans Verkuil q_data_cap->coded_height = coded_h; 1116efec9c81SHans Verkuil q_data_cap->sizeimage = size; 1117efec9c81SHans Verkuil } 1118efec9c81SHans Verkuil 1119256bf813SHans Verkuil switch (f->type) { 1120256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1121256bf813SHans Verkuil pix = &f->fmt.pix; 1122cd12b401SHans Verkuil ctx->state.colorspace = pix->colorspace; 1123cd12b401SHans Verkuil ctx->state.xfer_func = pix->xfer_func; 1124cd12b401SHans Verkuil ctx->state.ycbcr_enc = pix->ycbcr_enc; 1125cd12b401SHans Verkuil ctx->state.quantization = pix->quantization; 1126256bf813SHans Verkuil break; 1127256bf813SHans Verkuil case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 1128256bf813SHans Verkuil pix_mp = &f->fmt.pix_mp; 1129cd12b401SHans Verkuil ctx->state.colorspace = pix_mp->colorspace; 1130cd12b401SHans Verkuil ctx->state.xfer_func = pix_mp->xfer_func; 1131cd12b401SHans Verkuil ctx->state.ycbcr_enc = pix_mp->ycbcr_enc; 1132cd12b401SHans Verkuil ctx->state.quantization = pix_mp->quantization; 1133256bf813SHans Verkuil break; 1134256bf813SHans Verkuil default: 1135256bf813SHans Verkuil break; 1136256bf813SHans Verkuil } 1137256bf813SHans Verkuil } 1138256bf813SHans Verkuil return ret; 1139256bf813SHans Verkuil } 1140256bf813SHans Verkuil 11419e812549SDafna Hirschfeld static int vidioc_g_selection(struct file *file, void *priv, 11429e812549SDafna Hirschfeld struct v4l2_selection *s) 11439e812549SDafna Hirschfeld { 11449e812549SDafna Hirschfeld struct vicodec_ctx *ctx = file2ctx(file); 11459e812549SDafna Hirschfeld struct vicodec_q_data *q_data; 1146db9a01b3SHans Verkuil 11479e812549SDafna Hirschfeld q_data = get_q_data(ctx, s->type); 11489e812549SDafna Hirschfeld if (!q_data) 11499e812549SDafna Hirschfeld return -EINVAL; 11509e812549SDafna Hirschfeld /* 11519e812549SDafna Hirschfeld * encoder supports only cropping on the OUTPUT buffer 11529e812549SDafna Hirschfeld * decoder supports only composing on the CAPTURE buffer 11539e812549SDafna Hirschfeld */ 1154fb56f4beSHans Verkuil if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 1155fb56f4beSHans Verkuil switch (s->target) { 1156fb56f4beSHans Verkuil case V4L2_SEL_TGT_CROP: 1157fb56f4beSHans Verkuil s->r.left = 0; 1158fb56f4beSHans Verkuil s->r.top = 0; 1159fb56f4beSHans Verkuil s->r.width = q_data->visible_width; 1160fb56f4beSHans Verkuil s->r.height = q_data->visible_height; 1161fb56f4beSHans Verkuil return 0; 1162fb56f4beSHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT: 1163fb56f4beSHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS: 1164fb56f4beSHans Verkuil s->r.left = 0; 1165fb56f4beSHans Verkuil s->r.top = 0; 1166fb56f4beSHans Verkuil s->r.width = q_data->coded_width; 1167fb56f4beSHans Verkuil s->r.height = q_data->coded_height; 1168fb56f4beSHans Verkuil return 0; 1169fb56f4beSHans Verkuil } 1170fb56f4beSHans Verkuil } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 11719e812549SDafna Hirschfeld switch (s->target) { 11729e812549SDafna Hirschfeld case V4L2_SEL_TGT_COMPOSE: 11739e812549SDafna Hirschfeld s->r.left = 0; 11749e812549SDafna Hirschfeld s->r.top = 0; 11759e812549SDafna Hirschfeld s->r.width = q_data->visible_width; 11769e812549SDafna Hirschfeld s->r.height = q_data->visible_height; 11779e812549SDafna Hirschfeld return 0; 11789e812549SDafna Hirschfeld case V4L2_SEL_TGT_COMPOSE_DEFAULT: 11799e812549SDafna Hirschfeld case V4L2_SEL_TGT_COMPOSE_BOUNDS: 11809e812549SDafna Hirschfeld s->r.left = 0; 11819e812549SDafna Hirschfeld s->r.top = 0; 11829e812549SDafna Hirschfeld s->r.width = q_data->coded_width; 11839e812549SDafna Hirschfeld s->r.height = q_data->coded_height; 11849e812549SDafna Hirschfeld return 0; 11859e812549SDafna Hirschfeld } 11869e812549SDafna Hirschfeld } 11879e812549SDafna Hirschfeld return -EINVAL; 11889e812549SDafna Hirschfeld } 11899e812549SDafna Hirschfeld 11909e812549SDafna Hirschfeld static int vidioc_s_selection(struct file *file, void *priv, 11919e812549SDafna Hirschfeld struct v4l2_selection *s) 11929e812549SDafna Hirschfeld { 11939e812549SDafna Hirschfeld struct vicodec_ctx *ctx = file2ctx(file); 11949e812549SDafna Hirschfeld struct vicodec_q_data *q_data; 11959e812549SDafna Hirschfeld 11967243e5a0SDafna Hirschfeld if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 1197db9a01b3SHans Verkuil return -EINVAL; 1198db9a01b3SHans Verkuil 11999e812549SDafna Hirschfeld q_data = get_q_data(ctx, s->type); 12009e812549SDafna Hirschfeld if (!q_data) 12019e812549SDafna Hirschfeld return -EINVAL; 12029e812549SDafna Hirschfeld 1203db9a01b3SHans Verkuil if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP) 12049e812549SDafna Hirschfeld return -EINVAL; 12059e812549SDafna Hirschfeld 12069e812549SDafna Hirschfeld s->r.left = 0; 12079e812549SDafna Hirschfeld s->r.top = 0; 12089e812549SDafna Hirschfeld q_data->visible_width = clamp(s->r.width, MIN_WIDTH, 12099e812549SDafna Hirschfeld q_data->coded_width); 12109e812549SDafna Hirschfeld s->r.width = q_data->visible_width; 12119e812549SDafna Hirschfeld q_data->visible_height = clamp(s->r.height, MIN_HEIGHT, 12129e812549SDafna Hirschfeld q_data->coded_height); 12139e812549SDafna Hirschfeld s->r.height = q_data->visible_height; 12149e812549SDafna Hirschfeld return 0; 12159e812549SDafna Hirschfeld } 12169e812549SDafna Hirschfeld 1217256bf813SHans Verkuil static int vicodec_encoder_cmd(struct file *file, void *fh, 1218256bf813SHans Verkuil struct v4l2_encoder_cmd *ec) 1219256bf813SHans Verkuil { 1220256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 1221256bf813SHans Verkuil int ret; 1222256bf813SHans Verkuil 12239b925365SHans Verkuil ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); 1224256bf813SHans Verkuil if (ret < 0) 1225256bf813SHans Verkuil return ret; 1226256bf813SHans Verkuil 1227d17589afSHans Verkuil if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || 1228d17589afSHans Verkuil !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) 1229256bf813SHans Verkuil return 0; 1230d17589afSHans Verkuil 1231d4d137deSNeil Armstrong ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); 1232d4d137deSNeil Armstrong if (ret < 0) 1233d17589afSHans Verkuil return ret; 1234d4d137deSNeil Armstrong 1235d4d137deSNeil Armstrong if (ec->cmd == V4L2_ENC_CMD_STOP && 1236d4d137deSNeil Armstrong v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 1237d4d137deSNeil Armstrong v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); 1238d4d137deSNeil Armstrong 1239d4d137deSNeil Armstrong if (ec->cmd == V4L2_ENC_CMD_START && 1240d4d137deSNeil Armstrong v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 1241d4d137deSNeil Armstrong vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); 1242d4d137deSNeil Armstrong 1243d4d137deSNeil Armstrong return 0; 1244256bf813SHans Verkuil } 1245256bf813SHans Verkuil 1246256bf813SHans Verkuil static int vicodec_decoder_cmd(struct file *file, void *fh, 1247256bf813SHans Verkuil struct v4l2_decoder_cmd *dc) 1248256bf813SHans Verkuil { 1249256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 1250256bf813SHans Verkuil int ret; 1251256bf813SHans Verkuil 12529b925365SHans Verkuil ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); 1253256bf813SHans Verkuil if (ret < 0) 1254256bf813SHans Verkuil return ret; 1255256bf813SHans Verkuil 1256d17589afSHans Verkuil if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || 1257d17589afSHans Verkuil !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) 1258256bf813SHans Verkuil return 0; 1259d17589afSHans Verkuil 1260d4d137deSNeil Armstrong ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); 1261d4d137deSNeil Armstrong if (ret < 0) 1262d17589afSHans Verkuil return ret; 1263d4d137deSNeil Armstrong 1264d4d137deSNeil Armstrong if (dc->cmd == V4L2_DEC_CMD_STOP && 1265d4d137deSNeil Armstrong v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 1266d4d137deSNeil Armstrong v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); 1267d4d137deSNeil Armstrong 1268d4d137deSNeil Armstrong if (dc->cmd == V4L2_DEC_CMD_START && 1269d4d137deSNeil Armstrong v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 1270d4d137deSNeil Armstrong vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); 1271d4d137deSNeil Armstrong 1272d4d137deSNeil Armstrong return 0; 1273256bf813SHans Verkuil } 1274256bf813SHans Verkuil 1275256bf813SHans Verkuil static int vicodec_enum_framesizes(struct file *file, void *fh, 1276256bf813SHans Verkuil struct v4l2_frmsizeenum *fsize) 1277256bf813SHans Verkuil { 1278256bf813SHans Verkuil switch (fsize->pixel_format) { 127935e2e8b5SDafna Hirschfeld case V4L2_PIX_FMT_FWHT_STATELESS: 128035e2e8b5SDafna Hirschfeld break; 1281256bf813SHans Verkuil case V4L2_PIX_FMT_FWHT: 1282256bf813SHans Verkuil break; 1283256bf813SHans Verkuil default: 128429a7a5e9SHans Verkuil if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format) 1285256bf813SHans Verkuil break; 1286256bf813SHans Verkuil return -EINVAL; 1287256bf813SHans Verkuil } 1288256bf813SHans Verkuil 1289256bf813SHans Verkuil if (fsize->index) 1290256bf813SHans Verkuil return -EINVAL; 1291256bf813SHans Verkuil 1292256bf813SHans Verkuil fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 1293256bf813SHans Verkuil 1294256bf813SHans Verkuil fsize->stepwise.min_width = MIN_WIDTH; 1295256bf813SHans Verkuil fsize->stepwise.max_width = MAX_WIDTH; 1296256bf813SHans Verkuil fsize->stepwise.step_width = 8; 1297256bf813SHans Verkuil fsize->stepwise.min_height = MIN_HEIGHT; 1298256bf813SHans Verkuil fsize->stepwise.max_height = MAX_HEIGHT; 1299256bf813SHans Verkuil fsize->stepwise.step_height = 8; 1300256bf813SHans Verkuil 1301256bf813SHans Verkuil return 0; 1302256bf813SHans Verkuil } 1303256bf813SHans Verkuil 1304256bf813SHans Verkuil static int vicodec_subscribe_event(struct v4l2_fh *fh, 1305256bf813SHans Verkuil const struct v4l2_event_subscription *sub) 1306256bf813SHans Verkuil { 130769a90057SHans Verkuil struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh); 130869a90057SHans Verkuil 1309256bf813SHans Verkuil switch (sub->type) { 13103b15f68eSDafna Hirschfeld case V4L2_EVENT_SOURCE_CHANGE: 131169a90057SHans Verkuil if (ctx->is_enc) 131269a90057SHans Verkuil return -EINVAL; 13131771e9fbSGustavo A. R. Silva fallthrough; 131469a90057SHans Verkuil case V4L2_EVENT_EOS: 13153b6813d6SHans Verkuil if (ctx->is_stateless) 13163b6813d6SHans Verkuil return -EINVAL; 1317256bf813SHans Verkuil return v4l2_event_subscribe(fh, sub, 0, NULL); 1318256bf813SHans Verkuil default: 1319256bf813SHans Verkuil return v4l2_ctrl_subscribe_event(fh, sub); 1320256bf813SHans Verkuil } 1321256bf813SHans Verkuil } 1322256bf813SHans Verkuil 1323256bf813SHans Verkuil static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { 1324256bf813SHans Verkuil .vidioc_querycap = vidioc_querycap, 1325256bf813SHans Verkuil 1326256bf813SHans Verkuil .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 1327256bf813SHans Verkuil .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 1328256bf813SHans Verkuil .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 1329256bf813SHans Verkuil .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 1330256bf813SHans Verkuil 1331256bf813SHans Verkuil .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, 1332256bf813SHans Verkuil .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, 1333256bf813SHans Verkuil .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, 1334256bf813SHans Verkuil 1335256bf813SHans Verkuil .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, 1336256bf813SHans Verkuil .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, 1337256bf813SHans Verkuil .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, 1338256bf813SHans Verkuil .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, 1339256bf813SHans Verkuil 1340256bf813SHans Verkuil .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, 1341256bf813SHans Verkuil .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, 1342256bf813SHans Verkuil .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, 1343256bf813SHans Verkuil 1344256bf813SHans Verkuil .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 1345256bf813SHans Verkuil .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 1346256bf813SHans Verkuil .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 1347256bf813SHans Verkuil .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 1348256bf813SHans Verkuil .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 1349256bf813SHans Verkuil .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 1350256bf813SHans Verkuil .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 1351256bf813SHans Verkuil 1352256bf813SHans Verkuil .vidioc_streamon = v4l2_m2m_ioctl_streamon, 1353256bf813SHans Verkuil .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 1354256bf813SHans Verkuil 13559e812549SDafna Hirschfeld .vidioc_g_selection = vidioc_g_selection, 13569e812549SDafna Hirschfeld .vidioc_s_selection = vidioc_s_selection, 13579e812549SDafna Hirschfeld 13589b925365SHans Verkuil .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, 1359256bf813SHans Verkuil .vidioc_encoder_cmd = vicodec_encoder_cmd, 13609b925365SHans Verkuil .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, 1361256bf813SHans Verkuil .vidioc_decoder_cmd = vicodec_decoder_cmd, 1362256bf813SHans Verkuil .vidioc_enum_framesizes = vicodec_enum_framesizes, 1363256bf813SHans Verkuil 1364256bf813SHans Verkuil .vidioc_subscribe_event = vicodec_subscribe_event, 1365256bf813SHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1366256bf813SHans Verkuil }; 1367256bf813SHans Verkuil 1368256bf813SHans Verkuil 1369256bf813SHans Verkuil /* 1370256bf813SHans Verkuil * Queue operations 1371256bf813SHans Verkuil */ 1372256bf813SHans Verkuil 1373256bf813SHans Verkuil static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 1374256bf813SHans Verkuil unsigned int *nplanes, unsigned int sizes[], 1375256bf813SHans Verkuil struct device *alloc_devs[]) 1376256bf813SHans Verkuil { 1377256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(vq); 1378256bf813SHans Verkuil struct vicodec_q_data *q_data = get_q_data(ctx, vq->type); 1379256bf813SHans Verkuil unsigned int size = q_data->sizeimage; 1380256bf813SHans Verkuil 1381256bf813SHans Verkuil if (*nplanes) 1382256bf813SHans Verkuil return sizes[0] < size ? -EINVAL : 0; 1383256bf813SHans Verkuil 1384256bf813SHans Verkuil *nplanes = 1; 1385256bf813SHans Verkuil sizes[0] = size; 13868307f0abSHans Verkuil q_data->vb2_sizeimage = size; 1387256bf813SHans Verkuil return 0; 1388256bf813SHans Verkuil } 1389256bf813SHans Verkuil 1390997deb81SDafna Hirschfeld static int vicodec_buf_out_validate(struct vb2_buffer *vb) 1391997deb81SDafna Hirschfeld { 1392997deb81SDafna Hirschfeld struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1393997deb81SDafna Hirschfeld 1394997deb81SDafna Hirschfeld vbuf->field = V4L2_FIELD_NONE; 1395997deb81SDafna Hirschfeld return 0; 1396997deb81SDafna Hirschfeld } 1397997deb81SDafna Hirschfeld 1398256bf813SHans Verkuil static int vicodec_buf_prepare(struct vb2_buffer *vb) 1399256bf813SHans Verkuil { 1400256bf813SHans Verkuil struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1401256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1402256bf813SHans Verkuil struct vicodec_q_data *q_data; 1403256bf813SHans Verkuil 1404256bf813SHans Verkuil dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); 1405256bf813SHans Verkuil 1406256bf813SHans Verkuil q_data = get_q_data(ctx, vb->vb2_queue->type); 1407256bf813SHans Verkuil if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 1408256bf813SHans Verkuil if (vbuf->field == V4L2_FIELD_ANY) 1409256bf813SHans Verkuil vbuf->field = V4L2_FIELD_NONE; 1410256bf813SHans Verkuil if (vbuf->field != V4L2_FIELD_NONE) { 1411256bf813SHans Verkuil dprintk(ctx->dev, "%s field isn't supported\n", 1412256bf813SHans Verkuil __func__); 1413256bf813SHans Verkuil return -EINVAL; 1414256bf813SHans Verkuil } 1415256bf813SHans Verkuil } 1416256bf813SHans Verkuil 14178307f0abSHans Verkuil if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) { 1418256bf813SHans Verkuil dprintk(ctx->dev, 1419256bf813SHans Verkuil "%s data will not fit into plane (%lu < %lu)\n", 1420256bf813SHans Verkuil __func__, vb2_plane_size(vb, 0), 14218307f0abSHans Verkuil (long)q_data->vb2_sizeimage); 1422256bf813SHans Verkuil return -EINVAL; 1423256bf813SHans Verkuil } 1424256bf813SHans Verkuil 1425256bf813SHans Verkuil return 0; 1426256bf813SHans Verkuil } 1427256bf813SHans Verkuil 1428256bf813SHans Verkuil static void vicodec_buf_queue(struct vb2_buffer *vb) 1429256bf813SHans Verkuil { 1430256bf813SHans Verkuil struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1431256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 14323b15f68eSDafna Hirschfeld unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0); 14333b15f68eSDafna Hirschfeld u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0); 14343b15f68eSDafna Hirschfeld u8 *p = p_src; 14353b15f68eSDafna Hirschfeld struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 14363b15f68eSDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_OUTPUT); 14373b15f68eSDafna Hirschfeld struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 14383b15f68eSDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 14393b15f68eSDafna Hirschfeld bool header_valid = false; 14403b15f68eSDafna Hirschfeld static const struct v4l2_event rs_event = { 14413b15f68eSDafna Hirschfeld .type = V4L2_EVENT_SOURCE_CHANGE, 14423b15f68eSDafna Hirschfeld .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 14433b15f68eSDafna Hirschfeld }; 1444256bf813SHans Verkuil 1445b3ab1c60SEzequiel Garcia if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && 1446d4d137deSNeil Armstrong vb2_is_streaming(vb->vb2_queue) && 1447d4d137deSNeil Armstrong v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { 1448d17589afSHans Verkuil unsigned int i; 1449d17589afSHans Verkuil 1450d17589afSHans Verkuil for (i = 0; i < vb->num_planes; i++) 1451d17589afSHans Verkuil vb->planes[i].bytesused = 0; 1452d4d137deSNeil Armstrong 1453d17589afSHans Verkuil vbuf->field = V4L2_FIELD_NONE; 1454d4d137deSNeil Armstrong vbuf->sequence = 1455d4d137deSNeil Armstrong get_q_data(ctx, vb->vb2_queue->type)->sequence++; 1456d4d137deSNeil Armstrong 1457d4d137deSNeil Armstrong v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); 1458d17589afSHans Verkuil v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); 1459d17589afSHans Verkuil return; 1460d17589afSHans Verkuil } 1461d17589afSHans Verkuil 14623b15f68eSDafna Hirschfeld /* buf_queue handles only the first source change event */ 14633b15f68eSDafna Hirschfeld if (ctx->first_source_change_sent) { 14643b15f68eSDafna Hirschfeld v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 14653b15f68eSDafna Hirschfeld return; 14663b15f68eSDafna Hirschfeld } 14673b15f68eSDafna Hirschfeld 14683b15f68eSDafna Hirschfeld /* 14693b15f68eSDafna Hirschfeld * if both queues are streaming, the source change event is 14703b15f68eSDafna Hirschfeld * handled in job_ready 14713b15f68eSDafna Hirschfeld */ 14723b15f68eSDafna Hirschfeld if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) { 14733b15f68eSDafna Hirschfeld v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 14743b15f68eSDafna Hirschfeld return; 14753b15f68eSDafna Hirschfeld } 14763b15f68eSDafna Hirschfeld 14773b15f68eSDafna Hirschfeld /* 1478997deb81SDafna Hirschfeld * source change event is relevant only for the stateful decoder 14793b15f68eSDafna Hirschfeld * in the compressed stream 14803b15f68eSDafna Hirschfeld */ 1481997deb81SDafna Hirschfeld if (ctx->is_stateless || ctx->is_enc || 1482b3ab1c60SEzequiel Garcia V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { 14833b15f68eSDafna Hirschfeld v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 14843b15f68eSDafna Hirschfeld return; 14853b15f68eSDafna Hirschfeld } 14863b15f68eSDafna Hirschfeld 14873b15f68eSDafna Hirschfeld do { 14883b15f68eSDafna Hirschfeld enum vb2_buffer_state state = 14893b15f68eSDafna Hirschfeld get_next_header(ctx, &p, p_src + sz - p); 14903b15f68eSDafna Hirschfeld 14913b15f68eSDafna Hirschfeld if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { 14923b15f68eSDafna Hirschfeld v4l2_m2m_buf_done(vbuf, state); 14933b15f68eSDafna Hirschfeld return; 14943b15f68eSDafna Hirschfeld } 14953b15f68eSDafna Hirschfeld header_valid = is_header_valid(&ctx->state.header); 14963b15f68eSDafna Hirschfeld /* 14973b15f68eSDafna Hirschfeld * p points right after the end of the header in the 14983b15f68eSDafna Hirschfeld * buffer. If the header is invalid we set p to point 14993b15f68eSDafna Hirschfeld * to the next byte after the start of the header 15003b15f68eSDafna Hirschfeld */ 15013b15f68eSDafna Hirschfeld if (!header_valid) { 15023b15f68eSDafna Hirschfeld p = p - sizeof(struct fwht_cframe_hdr) + 1; 15033b15f68eSDafna Hirschfeld if (p < p_src) 15043b15f68eSDafna Hirschfeld p = p_src; 15053b15f68eSDafna Hirschfeld ctx->header_size = 0; 15063b15f68eSDafna Hirschfeld ctx->comp_magic_cnt = 0; 15073b15f68eSDafna Hirschfeld } 15083b15f68eSDafna Hirschfeld 15093b15f68eSDafna Hirschfeld } while (!header_valid); 15103b15f68eSDafna Hirschfeld 15113b15f68eSDafna Hirschfeld ctx->cur_buf_offset = p - p_src; 15123b15f68eSDafna Hirschfeld update_capture_data_from_header(ctx); 15133b15f68eSDafna Hirschfeld ctx->first_source_change_sent = true; 15143b15f68eSDafna Hirschfeld v4l2_event_queue_fh(&ctx->fh, &rs_event); 1515256bf813SHans Verkuil v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 1516256bf813SHans Verkuil } 1517256bf813SHans Verkuil 1518256bf813SHans Verkuil static void vicodec_return_bufs(struct vb2_queue *q, u32 state) 1519256bf813SHans Verkuil { 1520256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(q); 1521256bf813SHans Verkuil struct vb2_v4l2_buffer *vbuf; 1522256bf813SHans Verkuil 1523256bf813SHans Verkuil for (;;) { 1524256bf813SHans Verkuil if (V4L2_TYPE_IS_OUTPUT(q->type)) 1525256bf813SHans Verkuil vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 1526256bf813SHans Verkuil else 1527256bf813SHans Verkuil vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 1528256bf813SHans Verkuil if (vbuf == NULL) 1529256bf813SHans Verkuil return; 1530997deb81SDafna Hirschfeld v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, 1531997deb81SDafna Hirschfeld &ctx->hdl); 1532256bf813SHans Verkuil spin_lock(ctx->lock); 1533256bf813SHans Verkuil v4l2_m2m_buf_done(vbuf, state); 1534256bf813SHans Verkuil spin_unlock(ctx->lock); 1535256bf813SHans Verkuil } 1536256bf813SHans Verkuil } 1537256bf813SHans Verkuil 1538997deb81SDafna Hirschfeld static unsigned int total_frame_size(struct vicodec_q_data *q_data) 1539997deb81SDafna Hirschfeld { 1540997deb81SDafna Hirschfeld unsigned int size; 1541997deb81SDafna Hirschfeld unsigned int chroma_div; 1542997deb81SDafna Hirschfeld 1543997deb81SDafna Hirschfeld if (!q_data->info) { 1544997deb81SDafna Hirschfeld WARN_ON(1); 1545997deb81SDafna Hirschfeld return 0; 1546997deb81SDafna Hirschfeld } 1547997deb81SDafna Hirschfeld size = q_data->coded_width * q_data->coded_height; 1548997deb81SDafna Hirschfeld chroma_div = q_data->info->width_div * q_data->info->height_div; 1549997deb81SDafna Hirschfeld 1550997deb81SDafna Hirschfeld if (q_data->info->components_num == 4) 1551997deb81SDafna Hirschfeld return 2 * size + 2 * (size / chroma_div); 1552997deb81SDafna Hirschfeld else if (q_data->info->components_num == 3) 1553997deb81SDafna Hirschfeld return size + 2 * (size / chroma_div); 1554997deb81SDafna Hirschfeld return size; 1555997deb81SDafna Hirschfeld } 1556997deb81SDafna Hirschfeld 1557256bf813SHans Verkuil static int vicodec_start_streaming(struct vb2_queue *q, 1558256bf813SHans Verkuil unsigned int count) 1559256bf813SHans Verkuil { 1560256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(q); 1561256bf813SHans Verkuil struct vicodec_q_data *q_data = get_q_data(ctx, q->type); 1562cd12b401SHans Verkuil struct v4l2_fwht_state *state = &ctx->state; 1563cd12b401SHans Verkuil const struct v4l2_fwht_pixfmt_info *info = q_data->info; 15649e812549SDafna Hirschfeld unsigned int size = q_data->coded_width * q_data->coded_height; 15653b15f68eSDafna Hirschfeld unsigned int chroma_div; 156619505719SDafna Hirschfeld unsigned int total_planes_size; 1567997deb81SDafna Hirschfeld u8 *new_comp_frame = NULL; 156819505719SDafna Hirschfeld 15693b15f68eSDafna Hirschfeld chroma_div = info->width_div * info->height_div; 15703b15f68eSDafna Hirschfeld q_data->sequence = 0; 15713b15f68eSDafna Hirschfeld 1572d4d137deSNeil Armstrong v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); 157376eb24fcSHans Verkuil 15743b15f68eSDafna Hirschfeld state->gop_cnt = 0; 15753b15f68eSDafna Hirschfeld 15763b15f68eSDafna Hirschfeld if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || 1577b3ab1c60SEzequiel Garcia (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc)) 15783b15f68eSDafna Hirschfeld return 0; 15793b15f68eSDafna Hirschfeld 158035e2e8b5SDafna Hirschfeld if (info->id == V4L2_PIX_FMT_FWHT || 158135e2e8b5SDafna Hirschfeld info->id == V4L2_PIX_FMT_FWHT_STATELESS) { 15823b15f68eSDafna Hirschfeld vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); 15833b15f68eSDafna Hirschfeld return -EINVAL; 15843b15f68eSDafna Hirschfeld } 1585997deb81SDafna Hirschfeld total_planes_size = total_frame_size(q_data); 1586997deb81SDafna Hirschfeld ctx->comp_max_size = total_planes_size; 1587256bf813SHans Verkuil 15889e812549SDafna Hirschfeld state->visible_width = q_data->visible_width; 15899e812549SDafna Hirschfeld state->visible_height = q_data->visible_height; 15909e812549SDafna Hirschfeld state->coded_width = q_data->coded_width; 15919e812549SDafna Hirschfeld state->coded_height = q_data->coded_height; 15929e812549SDafna Hirschfeld state->stride = q_data->coded_width * 15939e812549SDafna Hirschfeld info->bytesperline_mult; 1594daa3fc44SHans Verkuil 1595997deb81SDafna Hirschfeld if (ctx->is_stateless) { 1596997deb81SDafna Hirschfeld state->ref_stride = state->stride; 1597997deb81SDafna Hirschfeld return 0; 1598997deb81SDafna Hirschfeld } 159986764b88SDafna Hirschfeld state->ref_stride = q_data->coded_width * info->luma_alpha_step; 1600997deb81SDafna Hirschfeld 1601bdbfd992SDafna Hirschfeld state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); 1602bdbfd992SDafna Hirschfeld state->ref_frame.luma = state->ref_frame.buf; 16033b15f68eSDafna Hirschfeld new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); 16043b15f68eSDafna Hirschfeld 16053b15f68eSDafna Hirschfeld if (!state->ref_frame.luma || !new_comp_frame) { 1606cd12b401SHans Verkuil kvfree(state->ref_frame.luma); 16073b15f68eSDafna Hirschfeld kvfree(new_comp_frame); 1608256bf813SHans Verkuil vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); 1609256bf813SHans Verkuil return -ENOMEM; 1610256bf813SHans Verkuil } 16113b15f68eSDafna Hirschfeld /* 16123b15f68eSDafna Hirschfeld * if state->compressed_frame was already allocated then 16133b15f68eSDafna Hirschfeld * it contain data of the first frame of the new resolution 16143b15f68eSDafna Hirschfeld */ 16153b15f68eSDafna Hirschfeld if (state->compressed_frame) { 16163b15f68eSDafna Hirschfeld if (ctx->comp_size > ctx->comp_max_size) 16173b15f68eSDafna Hirschfeld ctx->comp_size = ctx->comp_max_size; 16183b15f68eSDafna Hirschfeld 16193b15f68eSDafna Hirschfeld memcpy(new_comp_frame, 16203b15f68eSDafna Hirschfeld state->compressed_frame, ctx->comp_size); 16213b15f68eSDafna Hirschfeld } 16223b15f68eSDafna Hirschfeld 16233b15f68eSDafna Hirschfeld kvfree(state->compressed_frame); 16243b15f68eSDafna Hirschfeld state->compressed_frame = new_comp_frame; 16253b15f68eSDafna Hirschfeld 1626cb804507SMauro Carvalho Chehab if (info->components_num < 3) { 162719505719SDafna Hirschfeld state->ref_frame.cb = NULL; 162819505719SDafna Hirschfeld state->ref_frame.cr = NULL; 1629cb804507SMauro Carvalho Chehab state->ref_frame.alpha = NULL; 1630cb804507SMauro Carvalho Chehab return 0; 163119505719SDafna Hirschfeld } 163216ecf6dfSDafna Hirschfeld 1633cb804507SMauro Carvalho Chehab state->ref_frame.cb = state->ref_frame.luma + size; 1634cb804507SMauro Carvalho Chehab state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; 1635cb804507SMauro Carvalho Chehab 16363b15f68eSDafna Hirschfeld if (info->components_num == 4) 163716ecf6dfSDafna Hirschfeld state->ref_frame.alpha = 163816ecf6dfSDafna Hirschfeld state->ref_frame.cr + size / chroma_div; 163916ecf6dfSDafna Hirschfeld else 164016ecf6dfSDafna Hirschfeld state->ref_frame.alpha = NULL; 1641cb804507SMauro Carvalho Chehab 1642256bf813SHans Verkuil return 0; 1643256bf813SHans Verkuil } 1644256bf813SHans Verkuil 1645256bf813SHans Verkuil static void vicodec_stop_streaming(struct vb2_queue *q) 1646256bf813SHans Verkuil { 1647256bf813SHans Verkuil struct vicodec_ctx *ctx = vb2_get_drv_priv(q); 1648256bf813SHans Verkuil 1649256bf813SHans Verkuil vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); 1650256bf813SHans Verkuil 1651d4d137deSNeil Armstrong v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); 1652d17589afSHans Verkuil 1653d4d137deSNeil Armstrong if (V4L2_TYPE_IS_OUTPUT(q->type) && 1654d4d137deSNeil Armstrong v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 1655d17589afSHans Verkuil v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); 1656d4d137deSNeil Armstrong 1657d17589afSHans Verkuil if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) 1658d17589afSHans Verkuil ctx->first_source_change_sent = false; 1659d17589afSHans Verkuil 16603b15f68eSDafna Hirschfeld if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || 16613b15f68eSDafna Hirschfeld (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { 1662997deb81SDafna Hirschfeld if (!ctx->is_stateless) 1663bdbfd992SDafna Hirschfeld kvfree(ctx->state.ref_frame.buf); 1664bdbfd992SDafna Hirschfeld ctx->state.ref_frame.buf = NULL; 1665bdbfd992SDafna Hirschfeld ctx->state.ref_frame.luma = NULL; 16663b15f68eSDafna Hirschfeld ctx->comp_max_size = 0; 16673b15f68eSDafna Hirschfeld ctx->source_changed = false; 16683b15f68eSDafna Hirschfeld } 16693b15f68eSDafna Hirschfeld if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) { 16703b15f68eSDafna Hirschfeld ctx->cur_buf_offset = 0; 16713b15f68eSDafna Hirschfeld ctx->comp_size = 0; 16723b15f68eSDafna Hirschfeld ctx->header_size = 0; 16733b15f68eSDafna Hirschfeld ctx->comp_magic_cnt = 0; 1674333b90fbSDaniel W. S. Almeida ctx->comp_has_frame = false; 1675333b90fbSDaniel W. S. Almeida ctx->comp_has_next_frame = false; 16763b15f68eSDafna Hirschfeld } 1677256bf813SHans Verkuil } 1678256bf813SHans Verkuil 1679997deb81SDafna Hirschfeld static void vicodec_buf_request_complete(struct vb2_buffer *vb) 1680997deb81SDafna Hirschfeld { 1681997deb81SDafna Hirschfeld struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1682997deb81SDafna Hirschfeld 1683997deb81SDafna Hirschfeld v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); 1684997deb81SDafna Hirschfeld } 1685997deb81SDafna Hirschfeld 1686997deb81SDafna Hirschfeld 1687256bf813SHans Verkuil static const struct vb2_ops vicodec_qops = { 1688256bf813SHans Verkuil .queue_setup = vicodec_queue_setup, 1689997deb81SDafna Hirschfeld .buf_out_validate = vicodec_buf_out_validate, 1690256bf813SHans Verkuil .buf_prepare = vicodec_buf_prepare, 1691256bf813SHans Verkuil .buf_queue = vicodec_buf_queue, 1692997deb81SDafna Hirschfeld .buf_request_complete = vicodec_buf_request_complete, 1693256bf813SHans Verkuil .start_streaming = vicodec_start_streaming, 1694256bf813SHans Verkuil .stop_streaming = vicodec_stop_streaming, 1695256bf813SHans Verkuil .wait_prepare = vb2_ops_wait_prepare, 1696256bf813SHans Verkuil .wait_finish = vb2_ops_wait_finish, 1697256bf813SHans Verkuil }; 1698256bf813SHans Verkuil 1699256bf813SHans Verkuil static int queue_init(void *priv, struct vb2_queue *src_vq, 1700256bf813SHans Verkuil struct vb2_queue *dst_vq) 1701256bf813SHans Verkuil { 1702256bf813SHans Verkuil struct vicodec_ctx *ctx = priv; 1703256bf813SHans Verkuil int ret; 1704256bf813SHans Verkuil 1705256bf813SHans Verkuil src_vq->type = (multiplanar ? 1706256bf813SHans Verkuil V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : 1707256bf813SHans Verkuil V4L2_BUF_TYPE_VIDEO_OUTPUT); 1708256bf813SHans Verkuil src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 1709256bf813SHans Verkuil src_vq->drv_priv = ctx; 1710256bf813SHans Verkuil src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 1711256bf813SHans Verkuil src_vq->ops = &vicodec_qops; 1712256bf813SHans Verkuil src_vq->mem_ops = &vb2_vmalloc_memops; 1713256bf813SHans Verkuil src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 1714fde649b4SDafna Hirschfeld if (ctx->is_enc) 1715fde649b4SDafna Hirschfeld src_vq->lock = &ctx->dev->stateful_enc.mutex; 1716fde649b4SDafna Hirschfeld else if (ctx->is_stateless) 1717fde649b4SDafna Hirschfeld src_vq->lock = &ctx->dev->stateless_dec.mutex; 1718fde649b4SDafna Hirschfeld else 1719fde649b4SDafna Hirschfeld src_vq->lock = &ctx->dev->stateful_dec.mutex; 1720fde649b4SDafna Hirschfeld src_vq->supports_requests = ctx->is_stateless; 1721fde649b4SDafna Hirschfeld src_vq->requires_requests = ctx->is_stateless; 1722256bf813SHans Verkuil ret = vb2_queue_init(src_vq); 1723256bf813SHans Verkuil if (ret) 1724256bf813SHans Verkuil return ret; 1725256bf813SHans Verkuil 1726256bf813SHans Verkuil dst_vq->type = (multiplanar ? 1727256bf813SHans Verkuil V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : 1728256bf813SHans Verkuil V4L2_BUF_TYPE_VIDEO_CAPTURE); 1729256bf813SHans Verkuil dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 1730256bf813SHans Verkuil dst_vq->drv_priv = ctx; 1731256bf813SHans Verkuil dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 1732256bf813SHans Verkuil dst_vq->ops = &vicodec_qops; 1733256bf813SHans Verkuil dst_vq->mem_ops = &vb2_vmalloc_memops; 1734256bf813SHans Verkuil dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 1735256bf813SHans Verkuil dst_vq->lock = src_vq->lock; 1736256bf813SHans Verkuil 1737256bf813SHans Verkuil return vb2_queue_init(dst_vq); 1738256bf813SHans Verkuil } 1739256bf813SHans Verkuil 1740997deb81SDafna Hirschfeld static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) 1741997deb81SDafna Hirschfeld { 1742997deb81SDafna Hirschfeld struct vicodec_ctx *ctx = container_of(ctrl->handler, 1743997deb81SDafna Hirschfeld struct vicodec_ctx, hdl); 1744997deb81SDafna Hirschfeld const struct v4l2_ctrl_fwht_params *params; 1745997deb81SDafna Hirschfeld struct vicodec_q_data *q_dst = get_q_data(ctx, 1746997deb81SDafna Hirschfeld V4L2_BUF_TYPE_VIDEO_CAPTURE); 1747997deb81SDafna Hirschfeld 1748997deb81SDafna Hirschfeld switch (ctrl->id) { 1749997deb81SDafna Hirschfeld case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: 1750997deb81SDafna Hirschfeld if (!q_dst->info) 1751997deb81SDafna Hirschfeld return -EINVAL; 1752997deb81SDafna Hirschfeld params = ctrl->p_new.p_fwht_params; 1753997deb81SDafna Hirschfeld if (params->width > q_dst->coded_width || 1754997deb81SDafna Hirschfeld params->width < MIN_WIDTH || 1755997deb81SDafna Hirschfeld params->height > q_dst->coded_height || 1756997deb81SDafna Hirschfeld params->height < MIN_HEIGHT) 1757997deb81SDafna Hirschfeld return -EINVAL; 1758997deb81SDafna Hirschfeld if (!validate_by_version(params->flags, params->version)) 1759997deb81SDafna Hirschfeld return -EINVAL; 1760997deb81SDafna Hirschfeld if (!validate_stateless_params_flags(params, q_dst->info)) 1761997deb81SDafna Hirschfeld return -EINVAL; 1762997deb81SDafna Hirschfeld return 0; 1763997deb81SDafna Hirschfeld default: 1764997deb81SDafna Hirschfeld return 0; 1765997deb81SDafna Hirschfeld } 1766997deb81SDafna Hirschfeld return 0; 1767997deb81SDafna Hirschfeld } 1768997deb81SDafna Hirschfeld 1769997deb81SDafna Hirschfeld static void update_header_from_stateless_params(struct vicodec_ctx *ctx, 1770997deb81SDafna Hirschfeld const struct v4l2_ctrl_fwht_params *params) 1771997deb81SDafna Hirschfeld { 1772997deb81SDafna Hirschfeld struct fwht_cframe_hdr *p_hdr = &ctx->state.header; 1773997deb81SDafna Hirschfeld 1774997deb81SDafna Hirschfeld p_hdr->magic1 = FWHT_MAGIC1; 1775997deb81SDafna Hirschfeld p_hdr->magic2 = FWHT_MAGIC2; 1776997deb81SDafna Hirschfeld p_hdr->version = htonl(params->version); 1777997deb81SDafna Hirschfeld p_hdr->width = htonl(params->width); 1778997deb81SDafna Hirschfeld p_hdr->height = htonl(params->height); 1779997deb81SDafna Hirschfeld p_hdr->flags = htonl(params->flags); 1780997deb81SDafna Hirschfeld p_hdr->colorspace = htonl(params->colorspace); 1781997deb81SDafna Hirschfeld p_hdr->xfer_func = htonl(params->xfer_func); 1782997deb81SDafna Hirschfeld p_hdr->ycbcr_enc = htonl(params->ycbcr_enc); 1783997deb81SDafna Hirschfeld p_hdr->quantization = htonl(params->quantization); 1784997deb81SDafna Hirschfeld } 1785997deb81SDafna Hirschfeld 178648568b0cSHans Verkuil static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) 178748568b0cSHans Verkuil { 178848568b0cSHans Verkuil struct vicodec_ctx *ctx = container_of(ctrl->handler, 178948568b0cSHans Verkuil struct vicodec_ctx, hdl); 1790997deb81SDafna Hirschfeld const struct v4l2_ctrl_fwht_params *params; 179148568b0cSHans Verkuil 179248568b0cSHans Verkuil switch (ctrl->id) { 179348568b0cSHans Verkuil case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 1794cd12b401SHans Verkuil ctx->state.gop_size = ctrl->val; 179548568b0cSHans Verkuil return 0; 17962495f39cSDafna Hirschfeld case V4L2_CID_FWHT_I_FRAME_QP: 1797cd12b401SHans Verkuil ctx->state.i_frame_qp = ctrl->val; 179848568b0cSHans Verkuil return 0; 17992495f39cSDafna Hirschfeld case V4L2_CID_FWHT_P_FRAME_QP: 1800cd12b401SHans Verkuil ctx->state.p_frame_qp = ctrl->val; 180148568b0cSHans Verkuil return 0; 1802997deb81SDafna Hirschfeld case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: 1803997deb81SDafna Hirschfeld params = ctrl->p_new.p_fwht_params; 1804997deb81SDafna Hirschfeld update_header_from_stateless_params(ctx, params); 1805997deb81SDafna Hirschfeld ctx->state.ref_frame_ts = params->backward_ref_ts; 1806997deb81SDafna Hirschfeld return 0; 180748568b0cSHans Verkuil } 180848568b0cSHans Verkuil return -EINVAL; 180948568b0cSHans Verkuil } 181048568b0cSHans Verkuil 1811299553d8SJulia Lawall static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { 181248568b0cSHans Verkuil .s_ctrl = vicodec_s_ctrl, 1813997deb81SDafna Hirschfeld .try_ctrl = vicodec_try_ctrl, 181448568b0cSHans Verkuil }; 181548568b0cSHans Verkuil 18162495f39cSDafna Hirschfeld static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { 1817997deb81SDafna Hirschfeld .ops = &vicodec_ctrl_ops, 18182495f39cSDafna Hirschfeld .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, 18192495f39cSDafna Hirschfeld .elem_size = sizeof(struct v4l2_ctrl_fwht_params), 182048568b0cSHans Verkuil }; 182148568b0cSHans Verkuil 1822256bf813SHans Verkuil /* 1823256bf813SHans Verkuil * File operations 1824256bf813SHans Verkuil */ 1825256bf813SHans Verkuil static int vicodec_open(struct file *file) 1826256bf813SHans Verkuil { 1827d421ba0cSHans Verkuil const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0); 1828256bf813SHans Verkuil struct video_device *vfd = video_devdata(file); 1829256bf813SHans Verkuil struct vicodec_dev *dev = video_drvdata(file); 1830256bf813SHans Verkuil struct vicodec_ctx *ctx = NULL; 1831256bf813SHans Verkuil struct v4l2_ctrl_handler *hdl; 1832d421ba0cSHans Verkuil unsigned int raw_size; 1833d421ba0cSHans Verkuil unsigned int comp_size; 1834256bf813SHans Verkuil int rc = 0; 1835256bf813SHans Verkuil 1836256bf813SHans Verkuil if (mutex_lock_interruptible(vfd->lock)) 1837256bf813SHans Verkuil return -ERESTARTSYS; 1838256bf813SHans Verkuil ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 1839256bf813SHans Verkuil if (!ctx) { 1840256bf813SHans Verkuil rc = -ENOMEM; 1841256bf813SHans Verkuil goto open_unlock; 1842256bf813SHans Verkuil } 1843256bf813SHans Verkuil 1844c022a4a9SDafna Hirschfeld if (vfd == &dev->stateful_enc.vfd) 1845256bf813SHans Verkuil ctx->is_enc = true; 1846fde649b4SDafna Hirschfeld else if (vfd == &dev->stateless_dec.vfd) 1847fde649b4SDafna Hirschfeld ctx->is_stateless = true; 1848256bf813SHans Verkuil 1849256bf813SHans Verkuil v4l2_fh_init(&ctx->fh, video_devdata(file)); 1850256bf813SHans Verkuil file->private_data = &ctx->fh; 1851256bf813SHans Verkuil ctx->dev = dev; 1852256bf813SHans Verkuil hdl = &ctx->hdl; 1853358387d3SHans Verkuil v4l2_ctrl_handler_init(hdl, 5); 185448568b0cSHans Verkuil v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1855256bf813SHans Verkuil 1, 16, 1, 10); 18562495f39cSDafna Hirschfeld v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, 18572495f39cSDafna Hirschfeld 1, 31, 1, 20); 18582495f39cSDafna Hirschfeld v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, 18592495f39cSDafna Hirschfeld 1, 31, 1, 20); 1860358387d3SHans Verkuil if (ctx->is_enc) 1861358387d3SHans Verkuil v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, 1862358387d3SHans Verkuil V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); 1863fde649b4SDafna Hirschfeld if (ctx->is_stateless) 1864fde649b4SDafna Hirschfeld v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); 1865256bf813SHans Verkuil if (hdl->error) { 1866256bf813SHans Verkuil rc = hdl->error; 1867256bf813SHans Verkuil v4l2_ctrl_handler_free(hdl); 1868256bf813SHans Verkuil kfree(ctx); 1869256bf813SHans Verkuil goto open_unlock; 1870256bf813SHans Verkuil } 1871256bf813SHans Verkuil ctx->fh.ctrl_handler = hdl; 1872256bf813SHans Verkuil v4l2_ctrl_handler_setup(hdl); 1873256bf813SHans Verkuil 187435e2e8b5SDafna Hirschfeld if (ctx->is_enc) 1875d421ba0cSHans Verkuil ctx->q_data[V4L2_M2M_SRC].info = info; 187635e2e8b5SDafna Hirschfeld else if (ctx->is_stateless) 187735e2e8b5SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; 187835e2e8b5SDafna Hirschfeld else 187935e2e8b5SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht; 18809e812549SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; 18819e812549SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].coded_height = 720; 18829e812549SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; 18839e812549SDafna Hirschfeld ctx->q_data[V4L2_M2M_SRC].visible_height = 720; 1884d421ba0cSHans Verkuil raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; 1885d421ba0cSHans Verkuil comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / 1886d421ba0cSHans Verkuil pixfmt_fwht.sizeimage_div; 1887518f6b9aSHans Verkuil if (ctx->is_enc) 1888d421ba0cSHans Verkuil ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; 1889518f6b9aSHans Verkuil else if (ctx->is_stateless) 1890518f6b9aSHans Verkuil ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size; 189155f6fe09SHans Verkuil else 189255f6fe09SHans Verkuil ctx->q_data[V4L2_M2M_SRC].sizeimage = 1893d421ba0cSHans Verkuil comp_size + sizeof(struct fwht_cframe_hdr); 1894256bf813SHans Verkuil ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; 1895d421ba0cSHans Verkuil if (ctx->is_enc) { 18963b15f68eSDafna Hirschfeld ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; 1897d421ba0cSHans Verkuil ctx->q_data[V4L2_M2M_DST].sizeimage = 1898d421ba0cSHans Verkuil comp_size + sizeof(struct fwht_cframe_hdr); 18993b15f68eSDafna Hirschfeld } else { 1900d421ba0cSHans Verkuil ctx->q_data[V4L2_M2M_DST].info = info; 1901d421ba0cSHans Verkuil ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size; 19023b15f68eSDafna Hirschfeld } 19033b15f68eSDafna Hirschfeld 1904cd12b401SHans Verkuil ctx->state.colorspace = V4L2_COLORSPACE_REC709; 1905256bf813SHans Verkuil 1906256bf813SHans Verkuil if (ctx->is_enc) { 1907c022a4a9SDafna Hirschfeld ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev, 1908c022a4a9SDafna Hirschfeld ctx, &queue_init); 1909c022a4a9SDafna Hirschfeld ctx->lock = &dev->stateful_enc.lock; 1910fde649b4SDafna Hirschfeld } else if (ctx->is_stateless) { 1911fde649b4SDafna Hirschfeld ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev, 1912fde649b4SDafna Hirschfeld ctx, &queue_init); 1913fde649b4SDafna Hirschfeld ctx->lock = &dev->stateless_dec.lock; 1914256bf813SHans Verkuil } else { 1915c022a4a9SDafna Hirschfeld ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev, 1916c022a4a9SDafna Hirschfeld ctx, &queue_init); 1917c022a4a9SDafna Hirschfeld ctx->lock = &dev->stateful_dec.lock; 1918256bf813SHans Verkuil } 1919256bf813SHans Verkuil 1920256bf813SHans Verkuil if (IS_ERR(ctx->fh.m2m_ctx)) { 1921256bf813SHans Verkuil rc = PTR_ERR(ctx->fh.m2m_ctx); 1922256bf813SHans Verkuil 1923256bf813SHans Verkuil v4l2_ctrl_handler_free(hdl); 1924256bf813SHans Verkuil v4l2_fh_exit(&ctx->fh); 1925256bf813SHans Verkuil kfree(ctx); 1926256bf813SHans Verkuil goto open_unlock; 1927256bf813SHans Verkuil } 1928256bf813SHans Verkuil 1929256bf813SHans Verkuil v4l2_fh_add(&ctx->fh); 1930256bf813SHans Verkuil 1931256bf813SHans Verkuil open_unlock: 1932256bf813SHans Verkuil mutex_unlock(vfd->lock); 1933256bf813SHans Verkuil return rc; 1934256bf813SHans Verkuil } 1935256bf813SHans Verkuil 1936256bf813SHans Verkuil static int vicodec_release(struct file *file) 1937256bf813SHans Verkuil { 1938256bf813SHans Verkuil struct video_device *vfd = video_devdata(file); 1939256bf813SHans Verkuil struct vicodec_ctx *ctx = file2ctx(file); 1940256bf813SHans Verkuil 1941256bf813SHans Verkuil mutex_lock(vfd->lock); 1942256bf813SHans Verkuil v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 1943256bf813SHans Verkuil mutex_unlock(vfd->lock); 19444d10452cSDafna Hirschfeld v4l2_fh_del(&ctx->fh); 19454d10452cSDafna Hirschfeld v4l2_fh_exit(&ctx->fh); 19464d10452cSDafna Hirschfeld v4l2_ctrl_handler_free(&ctx->hdl); 1947a04a7a21SDafna Hirschfeld kvfree(ctx->state.compressed_frame); 1948256bf813SHans Verkuil kfree(ctx); 1949256bf813SHans Verkuil 1950256bf813SHans Verkuil return 0; 1951256bf813SHans Verkuil } 1952256bf813SHans Verkuil 1953997deb81SDafna Hirschfeld static int vicodec_request_validate(struct media_request *req) 1954997deb81SDafna Hirschfeld { 1955997deb81SDafna Hirschfeld struct media_request_object *obj; 1956997deb81SDafna Hirschfeld struct v4l2_ctrl_handler *parent_hdl, *hdl; 1957997deb81SDafna Hirschfeld struct vicodec_ctx *ctx = NULL; 1958997deb81SDafna Hirschfeld struct v4l2_ctrl *ctrl; 1959997deb81SDafna Hirschfeld unsigned int count; 1960997deb81SDafna Hirschfeld 1961997deb81SDafna Hirschfeld list_for_each_entry(obj, &req->objects, list) { 1962997deb81SDafna Hirschfeld struct vb2_buffer *vb; 1963997deb81SDafna Hirschfeld 1964997deb81SDafna Hirschfeld if (vb2_request_object_is_buffer(obj)) { 1965997deb81SDafna Hirschfeld vb = container_of(obj, struct vb2_buffer, req_obj); 1966997deb81SDafna Hirschfeld ctx = vb2_get_drv_priv(vb->vb2_queue); 1967997deb81SDafna Hirschfeld 1968997deb81SDafna Hirschfeld break; 1969997deb81SDafna Hirschfeld } 1970997deb81SDafna Hirschfeld } 1971997deb81SDafna Hirschfeld 1972997deb81SDafna Hirschfeld if (!ctx) { 1973997deb81SDafna Hirschfeld pr_err("No buffer was provided with the request\n"); 1974997deb81SDafna Hirschfeld return -ENOENT; 1975997deb81SDafna Hirschfeld } 1976997deb81SDafna Hirschfeld 1977997deb81SDafna Hirschfeld count = vb2_request_buffer_cnt(req); 1978997deb81SDafna Hirschfeld if (!count) { 1979997deb81SDafna Hirschfeld v4l2_info(&ctx->dev->v4l2_dev, 1980997deb81SDafna Hirschfeld "No buffer was provided with the request\n"); 1981997deb81SDafna Hirschfeld return -ENOENT; 1982997deb81SDafna Hirschfeld } else if (count > 1) { 1983997deb81SDafna Hirschfeld v4l2_info(&ctx->dev->v4l2_dev, 1984997deb81SDafna Hirschfeld "More than one buffer was provided with the request\n"); 1985997deb81SDafna Hirschfeld return -EINVAL; 1986997deb81SDafna Hirschfeld } 1987997deb81SDafna Hirschfeld 1988997deb81SDafna Hirschfeld parent_hdl = &ctx->hdl; 1989997deb81SDafna Hirschfeld 1990997deb81SDafna Hirschfeld hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); 1991997deb81SDafna Hirschfeld if (!hdl) { 1992997deb81SDafna Hirschfeld v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n"); 1993997deb81SDafna Hirschfeld return -ENOENT; 1994997deb81SDafna Hirschfeld } 1995997deb81SDafna Hirschfeld ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, 1996997deb81SDafna Hirschfeld vicodec_ctrl_stateless_state.id); 19972e7c8fb8SHans Verkuil v4l2_ctrl_request_hdl_put(hdl); 1998997deb81SDafna Hirschfeld if (!ctrl) { 1999997deb81SDafna Hirschfeld v4l2_info(&ctx->dev->v4l2_dev, 2000997deb81SDafna Hirschfeld "Missing required codec control\n"); 2001997deb81SDafna Hirschfeld return -ENOENT; 2002997deb81SDafna Hirschfeld } 2003997deb81SDafna Hirschfeld 2004997deb81SDafna Hirschfeld return vb2_request_validate(req); 2005997deb81SDafna Hirschfeld } 2006997deb81SDafna Hirschfeld 2007256bf813SHans Verkuil static const struct v4l2_file_operations vicodec_fops = { 2008256bf813SHans Verkuil .owner = THIS_MODULE, 2009256bf813SHans Verkuil .open = vicodec_open, 2010256bf813SHans Verkuil .release = vicodec_release, 2011256bf813SHans Verkuil .poll = v4l2_m2m_fop_poll, 2012256bf813SHans Verkuil .unlocked_ioctl = video_ioctl2, 2013256bf813SHans Verkuil .mmap = v4l2_m2m_fop_mmap, 2014256bf813SHans Verkuil }; 2015256bf813SHans Verkuil 2016256bf813SHans Verkuil static const struct video_device vicodec_videodev = { 2017256bf813SHans Verkuil .name = VICODEC_NAME, 2018256bf813SHans Verkuil .vfl_dir = VFL_DIR_M2M, 2019256bf813SHans Verkuil .fops = &vicodec_fops, 2020256bf813SHans Verkuil .ioctl_ops = &vicodec_ioctl_ops, 2021256bf813SHans Verkuil .minor = -1, 2022256bf813SHans Verkuil .release = video_device_release_empty, 2023256bf813SHans Verkuil }; 2024256bf813SHans Verkuil 2025997deb81SDafna Hirschfeld static const struct media_device_ops vicodec_m2m_media_ops = { 2026997deb81SDafna Hirschfeld .req_validate = vicodec_request_validate, 2027997deb81SDafna Hirschfeld .req_queue = v4l2_m2m_request_queue, 2028997deb81SDafna Hirschfeld }; 2029997deb81SDafna Hirschfeld 2030256bf813SHans Verkuil static const struct v4l2_m2m_ops m2m_ops = { 2031256bf813SHans Verkuil .device_run = device_run, 2032256bf813SHans Verkuil .job_ready = job_ready, 2033256bf813SHans Verkuil }; 2034256bf813SHans Verkuil 2035c022a4a9SDafna Hirschfeld static int register_instance(struct vicodec_dev *dev, 2036c022a4a9SDafna Hirschfeld struct vicodec_dev_instance *dev_instance, 2037c022a4a9SDafna Hirschfeld const char *name, bool is_enc) 2038c022a4a9SDafna Hirschfeld { 2039c022a4a9SDafna Hirschfeld struct video_device *vfd; 2040c022a4a9SDafna Hirschfeld int ret; 2041c022a4a9SDafna Hirschfeld 2042c022a4a9SDafna Hirschfeld spin_lock_init(&dev_instance->lock); 2043c022a4a9SDafna Hirschfeld mutex_init(&dev_instance->mutex); 2044c022a4a9SDafna Hirschfeld dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops); 2045c022a4a9SDafna Hirschfeld if (IS_ERR(dev_instance->m2m_dev)) { 2046c022a4a9SDafna Hirschfeld v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n"); 2047c022a4a9SDafna Hirschfeld return PTR_ERR(dev_instance->m2m_dev); 2048c022a4a9SDafna Hirschfeld } 2049c022a4a9SDafna Hirschfeld 2050c022a4a9SDafna Hirschfeld dev_instance->vfd = vicodec_videodev; 2051c022a4a9SDafna Hirschfeld vfd = &dev_instance->vfd; 2052c022a4a9SDafna Hirschfeld vfd->lock = &dev_instance->mutex; 2053c022a4a9SDafna Hirschfeld vfd->v4l2_dev = &dev->v4l2_dev; 2054c022a4a9SDafna Hirschfeld strscpy(vfd->name, name, sizeof(vfd->name)); 2055c022a4a9SDafna Hirschfeld vfd->device_caps = V4L2_CAP_STREAMING | 2056c022a4a9SDafna Hirschfeld (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); 2057c022a4a9SDafna Hirschfeld if (is_enc) { 2058c022a4a9SDafna Hirschfeld v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); 2059c022a4a9SDafna Hirschfeld v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); 2060c022a4a9SDafna Hirschfeld } else { 2061c022a4a9SDafna Hirschfeld v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); 2062c022a4a9SDafna Hirschfeld v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); 2063c022a4a9SDafna Hirschfeld } 2064c022a4a9SDafna Hirschfeld video_set_drvdata(vfd, dev); 2065c022a4a9SDafna Hirschfeld 206670cad449SHans Verkuil ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); 2067c022a4a9SDafna Hirschfeld if (ret) { 2068c022a4a9SDafna Hirschfeld v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name); 2069c022a4a9SDafna Hirschfeld v4l2_m2m_release(dev_instance->m2m_dev); 2070c022a4a9SDafna Hirschfeld return ret; 2071c022a4a9SDafna Hirschfeld } 2072c022a4a9SDafna Hirschfeld v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n", 2073c022a4a9SDafna Hirschfeld name, vfd->num); 2074c022a4a9SDafna Hirschfeld return 0; 2075c022a4a9SDafna Hirschfeld } 2076c022a4a9SDafna Hirschfeld 20770783525fSHans Verkuil static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) 20780783525fSHans Verkuil { 20790783525fSHans Verkuil struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev); 20800783525fSHans Verkuil 20810783525fSHans Verkuil v4l2_device_unregister(&dev->v4l2_dev); 20820783525fSHans Verkuil v4l2_m2m_release(dev->stateful_enc.m2m_dev); 20830783525fSHans Verkuil v4l2_m2m_release(dev->stateful_dec.m2m_dev); 20840783525fSHans Verkuil v4l2_m2m_release(dev->stateless_dec.m2m_dev); 2085693c5f14SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 2086693c5f14SHans Verkuil media_device_cleanup(&dev->mdev); 2087693c5f14SHans Verkuil #endif 20880783525fSHans Verkuil kfree(dev); 20890783525fSHans Verkuil } 20900783525fSHans Verkuil 2091256bf813SHans Verkuil static int vicodec_probe(struct platform_device *pdev) 2092256bf813SHans Verkuil { 2093256bf813SHans Verkuil struct vicodec_dev *dev; 2094256bf813SHans Verkuil int ret; 2095256bf813SHans Verkuil 20960783525fSHans Verkuil dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2097256bf813SHans Verkuil if (!dev) 2098256bf813SHans Verkuil return -ENOMEM; 2099256bf813SHans Verkuil 2100256bf813SHans Verkuil ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 2101256bf813SHans Verkuil if (ret) 21020783525fSHans Verkuil goto free_dev; 21030783525fSHans Verkuil 21040783525fSHans Verkuil dev->v4l2_dev.release = vicodec_v4l2_dev_release; 2105256bf813SHans Verkuil 2106256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 2107256bf813SHans Verkuil dev->mdev.dev = &pdev->dev; 2108c0decac1SMauro Carvalho Chehab strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model)); 21090247c75bSHans Verkuil strscpy(dev->mdev.bus_info, "platform:vicodec", 21100247c75bSHans Verkuil sizeof(dev->mdev.bus_info)); 2111256bf813SHans Verkuil media_device_init(&dev->mdev); 2112997deb81SDafna Hirschfeld dev->mdev.ops = &vicodec_m2m_media_ops; 2113256bf813SHans Verkuil dev->v4l2_dev.mdev = &dev->mdev; 2114256bf813SHans Verkuil #endif 2115256bf813SHans Verkuil 2116256bf813SHans Verkuil platform_set_drvdata(pdev, dev); 2117256bf813SHans Verkuil 2118f36592e7SDan Carpenter ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder", 2119f36592e7SDan Carpenter true); 2120f36592e7SDan Carpenter if (ret) 2121256bf813SHans Verkuil goto unreg_dev; 2122256bf813SHans Verkuil 2123f36592e7SDan Carpenter ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder", 2124f36592e7SDan Carpenter false); 2125f36592e7SDan Carpenter if (ret) 2126c022a4a9SDafna Hirschfeld goto unreg_sf_enc; 2127256bf813SHans Verkuil 2128f36592e7SDan Carpenter ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder", 2129f36592e7SDan Carpenter false); 2130f36592e7SDan Carpenter if (ret) 2131fde649b4SDafna Hirschfeld goto unreg_sf_dec; 2132fde649b4SDafna Hirschfeld 2133256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 2134c022a4a9SDafna Hirschfeld ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev, 2135c022a4a9SDafna Hirschfeld &dev->stateful_enc.vfd, 2136c022a4a9SDafna Hirschfeld MEDIA_ENT_F_PROC_VIDEO_ENCODER); 2137256bf813SHans Verkuil if (ret) { 2138c022a4a9SDafna Hirschfeld v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n"); 2139256bf813SHans Verkuil goto unreg_m2m; 2140256bf813SHans Verkuil } 2141256bf813SHans Verkuil 2142c022a4a9SDafna Hirschfeld ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev, 2143c022a4a9SDafna Hirschfeld &dev->stateful_dec.vfd, 2144c022a4a9SDafna Hirschfeld MEDIA_ENT_F_PROC_VIDEO_DECODER); 2145256bf813SHans Verkuil if (ret) { 2146c022a4a9SDafna Hirschfeld v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n"); 2147c022a4a9SDafna Hirschfeld goto unreg_m2m_sf_enc_mc; 2148256bf813SHans Verkuil } 2149256bf813SHans Verkuil 2150fde649b4SDafna Hirschfeld ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev, 2151fde649b4SDafna Hirschfeld &dev->stateless_dec.vfd, 2152fde649b4SDafna Hirschfeld MEDIA_ENT_F_PROC_VIDEO_DECODER); 2153fde649b4SDafna Hirschfeld if (ret) { 2154fde649b4SDafna Hirschfeld v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n"); 2155fde649b4SDafna Hirschfeld goto unreg_m2m_sf_dec_mc; 2156fde649b4SDafna Hirschfeld } 2157fde649b4SDafna Hirschfeld 2158256bf813SHans Verkuil ret = media_device_register(&dev->mdev); 2159256bf813SHans Verkuil if (ret) { 2160256bf813SHans Verkuil v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); 2161fde649b4SDafna Hirschfeld goto unreg_m2m_sl_dec_mc; 2162256bf813SHans Verkuil } 2163256bf813SHans Verkuil #endif 2164256bf813SHans Verkuil return 0; 2165256bf813SHans Verkuil 2166256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 2167fde649b4SDafna Hirschfeld unreg_m2m_sl_dec_mc: 2168fde649b4SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); 2169c022a4a9SDafna Hirschfeld unreg_m2m_sf_dec_mc: 2170c022a4a9SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); 2171c022a4a9SDafna Hirschfeld unreg_m2m_sf_enc_mc: 2172c022a4a9SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); 2173256bf813SHans Verkuil unreg_m2m: 2174fde649b4SDafna Hirschfeld video_unregister_device(&dev->stateless_dec.vfd); 2175fde649b4SDafna Hirschfeld v4l2_m2m_release(dev->stateless_dec.m2m_dev); 2176fde649b4SDafna Hirschfeld #endif 2177fde649b4SDafna Hirschfeld unreg_sf_dec: 2178c022a4a9SDafna Hirschfeld video_unregister_device(&dev->stateful_dec.vfd); 2179c022a4a9SDafna Hirschfeld v4l2_m2m_release(dev->stateful_dec.m2m_dev); 2180c022a4a9SDafna Hirschfeld unreg_sf_enc: 2181c022a4a9SDafna Hirschfeld video_unregister_device(&dev->stateful_enc.vfd); 2182c022a4a9SDafna Hirschfeld v4l2_m2m_release(dev->stateful_enc.m2m_dev); 2183256bf813SHans Verkuil unreg_dev: 2184256bf813SHans Verkuil v4l2_device_unregister(&dev->v4l2_dev); 21850783525fSHans Verkuil free_dev: 21860783525fSHans Verkuil kfree(dev); 2187256bf813SHans Verkuil 2188256bf813SHans Verkuil return ret; 2189256bf813SHans Verkuil } 2190256bf813SHans Verkuil 2191256bf813SHans Verkuil static int vicodec_remove(struct platform_device *pdev) 2192256bf813SHans Verkuil { 2193256bf813SHans Verkuil struct vicodec_dev *dev = platform_get_drvdata(pdev); 2194256bf813SHans Verkuil 2195256bf813SHans Verkuil v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME); 2196256bf813SHans Verkuil 2197256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER 2198256bf813SHans Verkuil media_device_unregister(&dev->mdev); 2199c022a4a9SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); 2200c022a4a9SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); 2201fde649b4SDafna Hirschfeld v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); 2202256bf813SHans Verkuil #endif 2203256bf813SHans Verkuil 2204c022a4a9SDafna Hirschfeld video_unregister_device(&dev->stateful_enc.vfd); 2205c022a4a9SDafna Hirschfeld video_unregister_device(&dev->stateful_dec.vfd); 2206fde649b4SDafna Hirschfeld video_unregister_device(&dev->stateless_dec.vfd); 22070783525fSHans Verkuil v4l2_device_put(&dev->v4l2_dev); 2208256bf813SHans Verkuil 2209256bf813SHans Verkuil return 0; 2210256bf813SHans Verkuil } 2211256bf813SHans Verkuil 2212256bf813SHans Verkuil static struct platform_driver vicodec_pdrv = { 2213256bf813SHans Verkuil .probe = vicodec_probe, 2214256bf813SHans Verkuil .remove = vicodec_remove, 2215256bf813SHans Verkuil .driver = { 2216256bf813SHans Verkuil .name = VICODEC_NAME, 2217256bf813SHans Verkuil }, 2218256bf813SHans Verkuil }; 2219256bf813SHans Verkuil 2220256bf813SHans Verkuil static void __exit vicodec_exit(void) 2221256bf813SHans Verkuil { 2222256bf813SHans Verkuil platform_driver_unregister(&vicodec_pdrv); 2223256bf813SHans Verkuil platform_device_unregister(&vicodec_pdev); 2224256bf813SHans Verkuil } 2225256bf813SHans Verkuil 2226256bf813SHans Verkuil static int __init vicodec_init(void) 2227256bf813SHans Verkuil { 2228256bf813SHans Verkuil int ret; 2229256bf813SHans Verkuil 2230256bf813SHans Verkuil ret = platform_device_register(&vicodec_pdev); 2231256bf813SHans Verkuil if (ret) 2232256bf813SHans Verkuil return ret; 2233256bf813SHans Verkuil 2234256bf813SHans Verkuil ret = platform_driver_register(&vicodec_pdrv); 2235256bf813SHans Verkuil if (ret) 2236256bf813SHans Verkuil platform_device_unregister(&vicodec_pdev); 2237256bf813SHans Verkuil 2238256bf813SHans Verkuil return ret; 2239256bf813SHans Verkuil } 2240256bf813SHans Verkuil 2241256bf813SHans Verkuil module_init(vicodec_init); 2242256bf813SHans Verkuil module_exit(vicodec_exit); 2243