1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022 MediaTek Inc. 4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> 5 */ 6 7 #include <linux/platform_device.h> 8 #include <media/v4l2-ioctl.h> 9 #include <media/v4l2-event.h> 10 #include <media/videobuf2-dma-contig.h> 11 #include "mtk-mdp3-m2m.h" 12 13 static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh) 14 { 15 return container_of(fh, struct mdp_m2m_ctx, fh); 16 } 17 18 static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) 19 { 20 return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler); 21 } 22 23 static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx, 24 enum v4l2_buf_type type) 25 { 26 if (V4L2_TYPE_IS_OUTPUT(type)) 27 return &ctx->curr_param.output; 28 else 29 return &ctx->curr_param.captures[0]; 30 } 31 32 static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state) 33 { 34 atomic_or(state, &ctx->curr_param.state); 35 } 36 37 static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask) 38 { 39 return ((atomic_read(&ctx->curr_param.state) & mask) == mask); 40 } 41 42 static void mdp_m2m_process_done(void *priv, int vb_state) 43 { 44 struct mdp_m2m_ctx *ctx = priv; 45 struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; 46 47 src_vbuf = (struct vb2_v4l2_buffer *) 48 v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 49 dst_vbuf = (struct vb2_v4l2_buffer *) 50 v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); 51 ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC]; 52 src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++; 53 dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++; 54 v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true); 55 56 v4l2_m2m_buf_done(src_vbuf, vb_state); 57 v4l2_m2m_buf_done(dst_vbuf, vb_state); 58 v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx); 59 } 60 61 static void mdp_m2m_device_run(void *priv) 62 { 63 struct mdp_m2m_ctx *ctx = priv; 64 struct mdp_frame *frame; 65 struct vb2_v4l2_buffer *src_vb, *dst_vb; 66 struct img_ipi_frameparam param = {}; 67 struct mdp_cmdq_param task = {}; 68 enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR; 69 int ret; 70 71 if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) { 72 dev_err(&ctx->mdp_dev->pdev->dev, 73 "mdp_m2m_ctx is in error state\n"); 74 goto worker_end; 75 } 76 77 param.frame_no = ctx->curr_param.frame_no; 78 param.type = ctx->curr_param.type; 79 param.num_inputs = 1; 80 param.num_outputs = 1; 81 82 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 83 src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); 84 mdp_set_src_config(¶m.inputs[0], frame, &src_vb->vb2_buf); 85 86 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 87 dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); 88 mdp_set_dst_config(¶m.outputs[0], frame, &dst_vb->vb2_buf); 89 90 ret = mdp_vpu_process(&ctx->vpu, ¶m); 91 if (ret) { 92 dev_err(&ctx->mdp_dev->pdev->dev, 93 "VPU MDP process failed: %d\n", ret); 94 goto worker_end; 95 } 96 97 task.config = ctx->vpu.config; 98 task.param = ¶m; 99 task.composes[0] = &frame->compose; 100 task.cmdq_cb = NULL; 101 task.cb_data = NULL; 102 task.mdp_ctx = ctx; 103 104 ret = mdp_cmdq_send(ctx->mdp_dev, &task); 105 if (ret) { 106 dev_err(&ctx->mdp_dev->pdev->dev, 107 "CMDQ sendtask failed: %d\n", ret); 108 goto worker_end; 109 } 110 111 return; 112 113 worker_end: 114 mdp_m2m_process_done(ctx, vb_state); 115 } 116 117 static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count) 118 { 119 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); 120 struct mdp_frame *capture; 121 struct vb2_queue *vq; 122 int ret; 123 bool out_streaming, cap_streaming; 124 125 if (V4L2_TYPE_IS_OUTPUT(q->type)) 126 ctx->frame_count[MDP_M2M_SRC] = 0; 127 128 if (V4L2_TYPE_IS_CAPTURE(q->type)) 129 ctx->frame_count[MDP_M2M_DST] = 0; 130 131 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 132 vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx); 133 out_streaming = vb2_is_streaming(vq); 134 vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); 135 cap_streaming = vb2_is_streaming(vq); 136 137 /* Check to see if scaling ratio is within supported range */ 138 if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) || 139 (V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) { 140 ret = mdp_check_scaling_ratio(&capture->crop.c, 141 &capture->compose, 142 capture->rotation, 143 ctx->curr_param.limit); 144 if (ret) { 145 dev_err(&ctx->mdp_dev->pdev->dev, 146 "Out of scaling range\n"); 147 return ret; 148 } 149 } 150 151 if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) { 152 ret = mdp_vpu_get_locked(ctx->mdp_dev); 153 if (ret) 154 return ret; 155 156 ret = mdp_vpu_ctx_init(&ctx->vpu, &ctx->mdp_dev->vpu, 157 MDP_DEV_M2M); 158 if (ret) { 159 dev_err(&ctx->mdp_dev->pdev->dev, 160 "VPU init failed %d\n", ret); 161 return -EINVAL; 162 } 163 mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT); 164 } 165 166 return 0; 167 } 168 169 static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx, 170 unsigned int type) 171 { 172 if (V4L2_TYPE_IS_OUTPUT(type)) 173 return (struct vb2_v4l2_buffer *) 174 v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 175 else 176 return (struct vb2_v4l2_buffer *) 177 v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); 178 } 179 180 static void mdp_m2m_stop_streaming(struct vb2_queue *q) 181 { 182 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); 183 struct vb2_v4l2_buffer *vb; 184 185 vb = mdp_m2m_buf_remove(ctx, q->type); 186 while (vb) { 187 v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); 188 vb = mdp_m2m_buf_remove(ctx, q->type); 189 } 190 } 191 192 static int mdp_m2m_queue_setup(struct vb2_queue *q, 193 unsigned int *num_buffers, 194 unsigned int *num_planes, unsigned int sizes[], 195 struct device *alloc_devs[]) 196 { 197 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); 198 struct v4l2_pix_format_mplane *pix_mp; 199 u32 i; 200 201 pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp; 202 203 /* from VIDIOC_CREATE_BUFS */ 204 if (*num_planes) { 205 if (*num_planes != pix_mp->num_planes) 206 return -EINVAL; 207 for (i = 0; i < pix_mp->num_planes; ++i) 208 if (sizes[i] < pix_mp->plane_fmt[i].sizeimage) 209 return -EINVAL; 210 } else {/* from VIDIOC_REQBUFS */ 211 *num_planes = pix_mp->num_planes; 212 for (i = 0; i < pix_mp->num_planes; ++i) 213 sizes[i] = pix_mp->plane_fmt[i].sizeimage; 214 } 215 216 return 0; 217 } 218 219 static int mdp_m2m_buf_prepare(struct vb2_buffer *vb) 220 { 221 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 222 struct v4l2_pix_format_mplane *pix_mp; 223 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 224 u32 i; 225 226 v4l2_buf->field = V4L2_FIELD_NONE; 227 228 if (V4L2_TYPE_IS_CAPTURE(vb->type)) { 229 pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp; 230 for (i = 0; i < pix_mp->num_planes; ++i) { 231 vb2_set_plane_payload(vb, i, 232 pix_mp->plane_fmt[i].sizeimage); 233 } 234 } 235 return 0; 236 } 237 238 static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb) 239 { 240 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 241 242 v4l2_buf->field = V4L2_FIELD_NONE; 243 244 return 0; 245 } 246 247 static void mdp_m2m_buf_queue(struct vb2_buffer *vb) 248 { 249 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 250 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 251 252 v4l2_buf->field = V4L2_FIELD_NONE; 253 254 v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); 255 } 256 257 static const struct vb2_ops mdp_m2m_qops = { 258 .queue_setup = mdp_m2m_queue_setup, 259 .wait_prepare = vb2_ops_wait_prepare, 260 .wait_finish = vb2_ops_wait_finish, 261 .buf_prepare = mdp_m2m_buf_prepare, 262 .start_streaming = mdp_m2m_start_streaming, 263 .stop_streaming = mdp_m2m_stop_streaming, 264 .buf_queue = mdp_m2m_buf_queue, 265 .buf_out_validate = mdp_m2m_buf_out_validate, 266 }; 267 268 static int mdp_m2m_querycap(struct file *file, void *fh, 269 struct v4l2_capability *cap) 270 { 271 strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver)); 272 strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card)); 273 274 return 0; 275 } 276 277 static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, 278 struct v4l2_fmtdesc *f) 279 { 280 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 281 282 return mdp_enum_fmt_mplane(ctx->mdp_dev, f); 283 } 284 285 static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, 286 struct v4l2_format *f) 287 { 288 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 289 struct mdp_frame *frame; 290 struct v4l2_pix_format_mplane *pix_mp; 291 292 frame = ctx_get_frame(ctx, f->type); 293 *f = frame->format; 294 pix_mp = &f->fmt.pix_mp; 295 pix_mp->colorspace = ctx->curr_param.colorspace; 296 pix_mp->xfer_func = ctx->curr_param.xfer_func; 297 pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc; 298 pix_mp->quantization = ctx->curr_param.quant; 299 300 return 0; 301 } 302 303 static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, 304 struct v4l2_format *f) 305 { 306 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 307 struct mdp_frame *frame = ctx_get_frame(ctx, f->type); 308 struct mdp_frame *capture; 309 const struct mdp_format *fmt; 310 struct vb2_queue *vq; 311 312 fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id); 313 if (!fmt) 314 return -EINVAL; 315 316 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); 317 if (vb2_is_busy(vq)) 318 return -EBUSY; 319 320 frame->format = *f; 321 frame->mdp_fmt = fmt; 322 frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color); 323 frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ? 324 MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP; 325 326 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 327 if (V4L2_TYPE_IS_OUTPUT(f->type)) { 328 capture->crop.c.left = 0; 329 capture->crop.c.top = 0; 330 capture->crop.c.width = f->fmt.pix_mp.width; 331 capture->crop.c.height = f->fmt.pix_mp.height; 332 ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace; 333 ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; 334 ctx->curr_param.quant = f->fmt.pix_mp.quantization; 335 ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func; 336 } else { 337 capture->compose.left = 0; 338 capture->compose.top = 0; 339 capture->compose.width = f->fmt.pix_mp.width; 340 capture->compose.height = f->fmt.pix_mp.height; 341 } 342 343 return 0; 344 } 345 346 static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, 347 struct v4l2_format *f) 348 { 349 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 350 351 if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id)) 352 return -EINVAL; 353 354 return 0; 355 } 356 357 static int mdp_m2m_g_selection(struct file *file, void *fh, 358 struct v4l2_selection *s) 359 { 360 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 361 struct mdp_frame *frame; 362 bool valid = false; 363 364 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 365 valid = mdp_target_is_crop(s->target); 366 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 367 valid = mdp_target_is_compose(s->target); 368 369 if (!valid) 370 return -EINVAL; 371 372 switch (s->target) { 373 case V4L2_SEL_TGT_CROP: 374 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 375 return -EINVAL; 376 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 377 s->r = frame->crop.c; 378 return 0; 379 case V4L2_SEL_TGT_COMPOSE: 380 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 381 return -EINVAL; 382 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 383 s->r = frame->compose; 384 return 0; 385 case V4L2_SEL_TGT_CROP_DEFAULT: 386 case V4L2_SEL_TGT_CROP_BOUNDS: 387 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 388 return -EINVAL; 389 frame = ctx_get_frame(ctx, s->type); 390 s->r.left = 0; 391 s->r.top = 0; 392 s->r.width = frame->format.fmt.pix_mp.width; 393 s->r.height = frame->format.fmt.pix_mp.height; 394 return 0; 395 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 396 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 397 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 398 return -EINVAL; 399 frame = ctx_get_frame(ctx, s->type); 400 s->r.left = 0; 401 s->r.top = 0; 402 s->r.width = frame->format.fmt.pix_mp.width; 403 s->r.height = frame->format.fmt.pix_mp.height; 404 return 0; 405 } 406 return -EINVAL; 407 } 408 409 static int mdp_m2m_s_selection(struct file *file, void *fh, 410 struct v4l2_selection *s) 411 { 412 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); 413 struct mdp_frame *frame = ctx_get_frame(ctx, s->type); 414 struct mdp_frame *capture; 415 struct v4l2_rect r; 416 struct device *dev = &ctx->mdp_dev->pdev->dev; 417 bool valid = false; 418 int ret; 419 420 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 421 valid = (s->target == V4L2_SEL_TGT_CROP); 422 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 423 valid = (s->target == V4L2_SEL_TGT_COMPOSE); 424 425 if (!valid) { 426 dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__, 427 ctx->id, s->type, s->target); 428 return -EINVAL; 429 } 430 431 ret = mdp_try_crop(ctx, &r, s, frame); 432 if (ret) 433 return ret; 434 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 435 436 if (mdp_target_is_crop(s->target)) 437 capture->crop.c = r; 438 else 439 capture->compose = r; 440 441 s->r = r; 442 443 return 0; 444 } 445 446 static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = { 447 .vidioc_querycap = mdp_m2m_querycap, 448 .vidioc_enum_fmt_vid_cap = mdp_m2m_enum_fmt_mplane, 449 .vidioc_enum_fmt_vid_out = mdp_m2m_enum_fmt_mplane, 450 .vidioc_g_fmt_vid_cap_mplane = mdp_m2m_g_fmt_mplane, 451 .vidioc_g_fmt_vid_out_mplane = mdp_m2m_g_fmt_mplane, 452 .vidioc_s_fmt_vid_cap_mplane = mdp_m2m_s_fmt_mplane, 453 .vidioc_s_fmt_vid_out_mplane = mdp_m2m_s_fmt_mplane, 454 .vidioc_try_fmt_vid_cap_mplane = mdp_m2m_try_fmt_mplane, 455 .vidioc_try_fmt_vid_out_mplane = mdp_m2m_try_fmt_mplane, 456 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 457 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 458 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 459 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 460 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 461 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 462 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 463 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 464 .vidioc_g_selection = mdp_m2m_g_selection, 465 .vidioc_s_selection = mdp_m2m_s_selection, 466 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 467 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 468 }; 469 470 static int mdp_m2m_queue_init(void *priv, 471 struct vb2_queue *src_vq, 472 struct vb2_queue *dst_vq) 473 { 474 struct mdp_m2m_ctx *ctx = priv; 475 int ret; 476 477 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 478 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 479 src_vq->ops = &mdp_m2m_qops; 480 src_vq->mem_ops = &vb2_dma_contig_memops; 481 src_vq->drv_priv = ctx; 482 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 483 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 484 src_vq->dev = &ctx->mdp_dev->pdev->dev; 485 src_vq->lock = &ctx->ctx_lock; 486 487 ret = vb2_queue_init(src_vq); 488 if (ret) 489 return ret; 490 491 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 492 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 493 dst_vq->ops = &mdp_m2m_qops; 494 dst_vq->mem_ops = &vb2_dma_contig_memops; 495 dst_vq->drv_priv = ctx; 496 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 497 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 498 dst_vq->dev = &ctx->mdp_dev->pdev->dev; 499 dst_vq->lock = &ctx->ctx_lock; 500 501 return vb2_queue_init(dst_vq); 502 } 503 504 static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl) 505 { 506 struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl); 507 struct mdp_frame *capture; 508 509 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 510 switch (ctrl->id) { 511 case V4L2_CID_HFLIP: 512 capture->hflip = ctrl->val; 513 break; 514 case V4L2_CID_VFLIP: 515 capture->vflip = ctrl->val; 516 break; 517 case V4L2_CID_ROTATE: 518 capture->rotation = ctrl->val; 519 break; 520 } 521 522 return 0; 523 } 524 525 static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = { 526 .s_ctrl = mdp_m2m_s_ctrl, 527 }; 528 529 static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx) 530 { 531 v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS); 532 ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 533 &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP, 534 0, 1, 1, 0); 535 ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 536 &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP, 537 0, 1, 1, 0); 538 ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, 539 &mdp_m2m_ctrl_ops, 540 V4L2_CID_ROTATE, 0, 270, 90, 0); 541 542 if (ctx->ctrl_handler.error) { 543 int err = ctx->ctrl_handler.error; 544 545 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 546 dev_err(&ctx->mdp_dev->pdev->dev, 547 "Failed to register controls\n"); 548 return err; 549 } 550 return 0; 551 } 552 553 static int mdp_m2m_open(struct file *file) 554 { 555 struct video_device *vdev = video_devdata(file); 556 struct mdp_dev *mdp = video_get_drvdata(vdev); 557 struct mdp_m2m_ctx *ctx; 558 struct device *dev = &mdp->pdev->dev; 559 int ret; 560 struct v4l2_format default_format = {}; 561 const struct mdp_limit *limit = mdp->mdp_data->def_limit; 562 563 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 564 if (!ctx) 565 return -ENOMEM; 566 567 if (mutex_lock_interruptible(&mdp->m2m_lock)) { 568 ret = -ERESTARTSYS; 569 goto err_free_ctx; 570 } 571 572 ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL); 573 if (ret < 0) 574 goto err_unlock_mutex; 575 ctx->id = ret; 576 577 ctx->mdp_dev = mdp; 578 579 v4l2_fh_init(&ctx->fh, vdev); 580 file->private_data = &ctx->fh; 581 ret = mdp_m2m_ctrls_create(ctx); 582 if (ret) 583 goto err_exit_fh; 584 585 /* Use separate control handler per file handle */ 586 ctx->fh.ctrl_handler = &ctx->ctrl_handler; 587 v4l2_fh_add(&ctx->fh); 588 589 mutex_init(&ctx->ctx_lock); 590 ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init); 591 if (IS_ERR(ctx->m2m_ctx)) { 592 dev_err(dev, "Failed to initialize m2m context\n"); 593 ret = PTR_ERR(ctx->m2m_ctx); 594 goto err_release_handler; 595 } 596 ctx->fh.m2m_ctx = ctx->m2m_ctx; 597 598 ctx->curr_param.ctx = ctx; 599 ret = mdp_frameparam_init(mdp, &ctx->curr_param); 600 if (ret) { 601 dev_err(dev, "Failed to initialize mdp parameter\n"); 602 goto err_release_m2m_ctx; 603 } 604 605 mutex_unlock(&mdp->m2m_lock); 606 607 /* Default format */ 608 default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 609 default_format.fmt.pix_mp.width = limit->out_limit.wmin; 610 default_format.fmt.pix_mp.height = limit->out_limit.hmin; 611 default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M; 612 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); 613 default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 614 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); 615 616 dev_dbg(dev, "%s:[%d]", __func__, ctx->id); 617 618 return 0; 619 620 err_release_m2m_ctx: 621 v4l2_m2m_ctx_release(ctx->m2m_ctx); 622 err_release_handler: 623 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 624 v4l2_fh_del(&ctx->fh); 625 err_exit_fh: 626 v4l2_fh_exit(&ctx->fh); 627 ida_free(&mdp->mdp_ida, ctx->id); 628 err_unlock_mutex: 629 mutex_unlock(&mdp->m2m_lock); 630 err_free_ctx: 631 kfree(ctx); 632 633 return ret; 634 } 635 636 static int mdp_m2m_release(struct file *file) 637 { 638 struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data); 639 struct mdp_dev *mdp = video_drvdata(file); 640 struct device *dev = &mdp->pdev->dev; 641 642 mutex_lock(&mdp->m2m_lock); 643 v4l2_m2m_ctx_release(ctx->m2m_ctx); 644 if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) { 645 mdp_vpu_ctx_deinit(&ctx->vpu); 646 mdp_vpu_put_locked(mdp); 647 } 648 649 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 650 v4l2_fh_del(&ctx->fh); 651 v4l2_fh_exit(&ctx->fh); 652 ida_free(&mdp->mdp_ida, ctx->id); 653 mutex_unlock(&mdp->m2m_lock); 654 655 dev_dbg(dev, "%s:[%d]", __func__, ctx->id); 656 kfree(ctx); 657 658 return 0; 659 } 660 661 static const struct v4l2_file_operations mdp_m2m_fops = { 662 .owner = THIS_MODULE, 663 .poll = v4l2_m2m_fop_poll, 664 .unlocked_ioctl = video_ioctl2, 665 .mmap = v4l2_m2m_fop_mmap, 666 .open = mdp_m2m_open, 667 .release = mdp_m2m_release, 668 }; 669 670 static const struct v4l2_m2m_ops mdp_m2m_ops = { 671 .device_run = mdp_m2m_device_run, 672 }; 673 674 int mdp_m2m_device_register(struct mdp_dev *mdp) 675 { 676 struct device *dev = &mdp->pdev->dev; 677 int ret = 0; 678 679 mdp->m2m_vdev = video_device_alloc(); 680 if (!mdp->m2m_vdev) { 681 dev_err(dev, "Failed to allocate video device\n"); 682 ret = -ENOMEM; 683 goto err_video_alloc; 684 } 685 mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | 686 V4L2_CAP_STREAMING; 687 mdp->m2m_vdev->fops = &mdp_m2m_fops; 688 mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops; 689 mdp->m2m_vdev->release = mdp_video_device_release; 690 mdp->m2m_vdev->lock = &mdp->m2m_lock; 691 mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M; 692 mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev; 693 snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m", 694 MDP_MODULE_NAME); 695 video_set_drvdata(mdp->m2m_vdev, mdp); 696 697 mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops); 698 if (IS_ERR(mdp->m2m_dev)) { 699 dev_err(dev, "Failed to initialize v4l2-m2m device\n"); 700 ret = PTR_ERR(mdp->m2m_dev); 701 goto err_m2m_init; 702 } 703 704 ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1); 705 if (ret) { 706 dev_err(dev, "Failed to register video device\n"); 707 goto err_video_register; 708 } 709 710 v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d", 711 mdp->m2m_vdev->num); 712 return 0; 713 714 err_video_register: 715 v4l2_m2m_release(mdp->m2m_dev); 716 err_m2m_init: 717 video_device_release(mdp->m2m_vdev); 718 err_video_alloc: 719 720 return ret; 721 } 722 723 void mdp_m2m_device_unregister(struct mdp_dev *mdp) 724 { 725 video_unregister_device(mdp->m2m_vdev); 726 } 727 728 void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx) 729 { 730 enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE; 731 732 mdp_m2m_process_done(ctx, vb_state); 733 } 734