1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ISI V4L2 memory to memory driver for i.MX8QXP/QM platform 4 * 5 * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which 6 * used to process image from camera sensor or memory to memory or DC 7 * 8 * Copyright (c) 2019 NXP Semiconductor 9 */ 10 11 #include <linux/container_of.h> 12 #include <linux/device.h> 13 #include <linux/errno.h> 14 #include <linux/kernel.h> 15 #include <linux/limits.h> 16 #include <linux/minmax.h> 17 #include <linux/mutex.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/slab.h> 20 #include <linux/spinlock.h> 21 #include <linux/string.h> 22 #include <linux/types.h> 23 #include <linux/videodev2.h> 24 25 #include <media/media-entity.h> 26 #include <media/v4l2-ctrls.h> 27 #include <media/v4l2-device.h> 28 #include <media/v4l2-event.h> 29 #include <media/v4l2-fh.h> 30 #include <media/v4l2-ioctl.h> 31 #include <media/v4l2-mem2mem.h> 32 #include <media/videobuf2-core.h> 33 #include <media/videobuf2-dma-contig.h> 34 35 #include "imx8-isi-core.h" 36 37 struct mxc_isi_m2m_buffer { 38 struct v4l2_m2m_buffer buf; 39 dma_addr_t dma_addrs[3]; 40 }; 41 42 struct mxc_isi_m2m_ctx_queue_data { 43 struct v4l2_pix_format_mplane format; 44 const struct mxc_isi_format_info *info; 45 u32 sequence; 46 }; 47 48 struct mxc_isi_m2m_ctx { 49 struct v4l2_fh fh; 50 struct mxc_isi_m2m *m2m; 51 52 /* Protects the m2m vb2 queues */ 53 struct mutex vb2_lock; 54 55 struct { 56 struct mxc_isi_m2m_ctx_queue_data out; 57 struct mxc_isi_m2m_ctx_queue_data cap; 58 } queues; 59 60 struct { 61 struct v4l2_ctrl_handler handler; 62 unsigned int alpha; 63 bool hflip; 64 bool vflip; 65 } ctrls; 66 67 bool chained; 68 }; 69 70 static inline struct mxc_isi_m2m_buffer * 71 to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf) 72 { 73 return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb); 74 } 75 76 static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh) 77 { 78 return container_of(fh, struct mxc_isi_m2m_ctx, fh); 79 } 80 81 static inline struct mxc_isi_m2m_ctx_queue_data * 82 mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx *ctx, enum v4l2_buf_type type) 83 { 84 if (V4L2_TYPE_IS_OUTPUT(type)) 85 return &ctx->queues.out; 86 else 87 return &ctx->queues.cap; 88 } 89 90 /* ----------------------------------------------------------------------------- 91 * V4L2 M2M device operations 92 */ 93 94 static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe *pipe, u32 status) 95 { 96 struct mxc_isi_m2m *m2m = &pipe->isi->m2m; 97 struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; 98 struct mxc_isi_m2m_ctx *ctx; 99 100 ctx = v4l2_m2m_get_curr_priv(m2m->m2m_dev); 101 if (!ctx) { 102 dev_err(m2m->isi->dev, 103 "Instance released before the end of transaction\n"); 104 return; 105 } 106 107 src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 108 dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 109 110 v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, false); 111 112 src_vbuf->sequence = ctx->queues.out.sequence++; 113 dst_vbuf->sequence = ctx->queues.cap.sequence++; 114 115 v4l2_m2m_buf_done(src_vbuf, VB2_BUF_STATE_DONE); 116 v4l2_m2m_buf_done(dst_vbuf, VB2_BUF_STATE_DONE); 117 118 v4l2_m2m_job_finish(m2m->m2m_dev, ctx->fh.m2m_ctx); 119 } 120 121 static void mxc_isi_m2m_device_run(void *priv) 122 { 123 struct mxc_isi_m2m_ctx *ctx = priv; 124 struct mxc_isi_m2m *m2m = ctx->m2m; 125 struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; 126 struct mxc_isi_m2m_buffer *src_buf, *dst_buf; 127 128 mxc_isi_channel_disable(m2m->pipe); 129 130 mutex_lock(&m2m->lock); 131 132 /* If the context has changed, reconfigure the channel. */ 133 if (m2m->last_ctx != ctx) { 134 const struct v4l2_area in_size = { 135 .width = ctx->queues.out.format.width, 136 .height = ctx->queues.out.format.height, 137 }; 138 const struct v4l2_area scale = { 139 .width = ctx->queues.cap.format.width, 140 .height = ctx->queues.cap.format.height, 141 }; 142 const struct v4l2_rect crop = { 143 .width = ctx->queues.cap.format.width, 144 .height = ctx->queues.cap.format.height, 145 }; 146 147 mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM, 148 &in_size, &scale, &crop, 149 ctx->queues.out.info->encoding, 150 ctx->queues.cap.info->encoding); 151 mxc_isi_channel_set_input_format(m2m->pipe, 152 ctx->queues.out.info, 153 &ctx->queues.out.format); 154 mxc_isi_channel_set_output_format(m2m->pipe, 155 ctx->queues.cap.info, 156 &ctx->queues.cap.format); 157 158 m2m->last_ctx = ctx; 159 } 160 161 mutex_unlock(&m2m->lock); 162 163 mutex_lock(ctx->ctrls.handler.lock); 164 mxc_isi_channel_set_alpha(m2m->pipe, ctx->ctrls.alpha); 165 mxc_isi_channel_set_flip(m2m->pipe, ctx->ctrls.hflip, ctx->ctrls.vflip); 166 mutex_unlock(ctx->ctrls.handler.lock); 167 168 src_vbuf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 169 dst_vbuf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 170 171 src_buf = to_isi_m2m_buffer(src_vbuf); 172 dst_buf = to_isi_m2m_buffer(dst_vbuf); 173 174 mxc_isi_channel_set_inbuf(m2m->pipe, src_buf->dma_addrs[0]); 175 mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF1); 176 mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF2); 177 178 mxc_isi_channel_enable(m2m->pipe); 179 180 mxc_isi_channel_m2m_start(m2m->pipe); 181 } 182 183 static const struct v4l2_m2m_ops mxc_isi_m2m_ops = { 184 .device_run = mxc_isi_m2m_device_run, 185 }; 186 187 /* ----------------------------------------------------------------------------- 188 * videobuf2 queue operations 189 */ 190 191 static int mxc_isi_m2m_vb2_queue_setup(struct vb2_queue *q, 192 unsigned int *num_buffers, 193 unsigned int *num_planes, 194 unsigned int sizes[], 195 struct device *alloc_devs[]) 196 { 197 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q); 198 const struct mxc_isi_m2m_ctx_queue_data *qdata = 199 mxc_isi_m2m_ctx_qdata(ctx, q->type); 200 201 return mxc_isi_video_queue_setup(&qdata->format, qdata->info, 202 num_buffers, num_planes, sizes); 203 } 204 205 static int mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer *vb2) 206 { 207 struct vb2_queue *vq = vb2->vb2_queue; 208 struct mxc_isi_m2m_buffer *buf = to_isi_m2m_buffer(to_vb2_v4l2_buffer(vb2)); 209 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue); 210 const struct mxc_isi_m2m_ctx_queue_data *qdata = 211 mxc_isi_m2m_ctx_qdata(ctx, vq->type); 212 213 mxc_isi_video_buffer_init(vb2, buf->dma_addrs, qdata->info, 214 &qdata->format); 215 216 return 0; 217 } 218 219 static int mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer *vb2) 220 { 221 struct vb2_queue *vq = vb2->vb2_queue; 222 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vq); 223 const struct mxc_isi_m2m_ctx_queue_data *qdata = 224 mxc_isi_m2m_ctx_qdata(ctx, vq->type); 225 226 return mxc_isi_video_buffer_prepare(ctx->m2m->isi, vb2, qdata->info, 227 &qdata->format); 228 } 229 230 static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2) 231 { 232 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); 233 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue); 234 235 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 236 } 237 238 static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q, 239 unsigned int count) 240 { 241 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q); 242 struct mxc_isi_m2m_ctx_queue_data *qdata = 243 mxc_isi_m2m_ctx_qdata(ctx, q->type); 244 245 qdata->sequence = 0; 246 247 return 0; 248 } 249 250 static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q) 251 { 252 struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q); 253 struct vb2_v4l2_buffer *vbuf; 254 255 for (;;) { 256 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 257 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 258 else 259 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 260 if (!vbuf) 261 break; 262 263 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); 264 } 265 } 266 267 static const struct vb2_ops mxc_isi_m2m_vb2_qops = { 268 .queue_setup = mxc_isi_m2m_vb2_queue_setup, 269 .buf_init = mxc_isi_m2m_vb2_buffer_init, 270 .buf_prepare = mxc_isi_m2m_vb2_buffer_prepare, 271 .buf_queue = mxc_isi_m2m_vb2_buffer_queue, 272 .wait_prepare = vb2_ops_wait_prepare, 273 .wait_finish = vb2_ops_wait_finish, 274 .start_streaming = mxc_isi_m2m_vb2_start_streaming, 275 .stop_streaming = mxc_isi_m2m_vb2_stop_streaming, 276 }; 277 278 static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq, 279 struct vb2_queue *dst_vq) 280 { 281 struct mxc_isi_m2m_ctx *ctx = priv; 282 struct mxc_isi_m2m *m2m = ctx->m2m; 283 int ret; 284 285 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 286 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 287 src_vq->drv_priv = ctx; 288 src_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer); 289 src_vq->ops = &mxc_isi_m2m_vb2_qops; 290 src_vq->mem_ops = &vb2_dma_contig_memops; 291 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 292 src_vq->lock = &ctx->vb2_lock; 293 src_vq->dev = m2m->isi->dev; 294 295 ret = vb2_queue_init(src_vq); 296 if (ret) 297 return ret; 298 299 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 300 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 301 dst_vq->drv_priv = ctx; 302 dst_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer); 303 dst_vq->ops = &mxc_isi_m2m_vb2_qops; 304 dst_vq->mem_ops = &vb2_dma_contig_memops; 305 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 306 dst_vq->lock = &ctx->vb2_lock; 307 dst_vq->dev = m2m->isi->dev; 308 309 return vb2_queue_init(dst_vq); 310 } 311 312 /* ----------------------------------------------------------------------------- 313 * V4L2 controls 314 */ 315 316 static inline struct mxc_isi_m2m_ctx * 317 ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl *ctrl) 318 { 319 return container_of(ctrl->handler, struct mxc_isi_m2m_ctx, ctrls.handler); 320 } 321 322 static int mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl *ctrl) 323 { 324 struct mxc_isi_m2m_ctx *ctx = ctrl_to_mxc_isi_m2m_ctx(ctrl); 325 326 switch (ctrl->id) { 327 case V4L2_CID_HFLIP: 328 ctx->ctrls.hflip = ctrl->val; 329 break; 330 331 case V4L2_CID_VFLIP: 332 ctx->ctrls.vflip = ctrl->val; 333 break; 334 335 case V4L2_CID_ALPHA_COMPONENT: 336 ctx->ctrls.alpha = ctrl->val; 337 break; 338 } 339 340 return 0; 341 } 342 343 static const struct v4l2_ctrl_ops mxc_isi_m2m_ctx_ctrl_ops = { 344 .s_ctrl = mxc_isi_m2m_ctx_s_ctrl, 345 }; 346 347 static int mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx *ctx) 348 { 349 struct v4l2_ctrl_handler *handler = &ctx->ctrls.handler; 350 int ret; 351 352 v4l2_ctrl_handler_init(handler, 3); 353 354 v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops, 355 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); 356 v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops, 357 V4L2_CID_HFLIP, 0, 1, 1, 0); 358 v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops, 359 V4L2_CID_VFLIP, 0, 1, 1, 0); 360 361 if (handler->error) { 362 ret = handler->error; 363 v4l2_ctrl_handler_free(handler); 364 return ret; 365 } 366 367 ctx->fh.ctrl_handler = handler; 368 369 return 0; 370 } 371 372 static void mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx *ctx) 373 { 374 v4l2_ctrl_handler_free(&ctx->ctrls.handler); 375 } 376 377 /* ----------------------------------------------------------------------------- 378 * V4L2 ioctls 379 */ 380 381 static int mxc_isi_m2m_querycap(struct file *file, void *fh, 382 struct v4l2_capability *cap) 383 { 384 strscpy(cap->driver, MXC_ISI_DRIVER_NAME, sizeof(cap->driver)); 385 strscpy(cap->card, MXC_ISI_M2M, sizeof(cap->card)); 386 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; 387 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 388 389 return 0; 390 } 391 392 static int mxc_isi_m2m_enum_fmt_vid(struct file *file, void *fh, 393 struct v4l2_fmtdesc *f) 394 { 395 const enum mxc_isi_video_type type = 396 f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? 397 MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; 398 const struct mxc_isi_format_info *info; 399 400 info = mxc_isi_format_enum(f->index, type); 401 if (!info) 402 return -EINVAL; 403 404 f->pixelformat = info->fourcc; 405 f->flags |= V4L2_FMT_FLAG_CSC_COLORSPACE | V4L2_FMT_FLAG_CSC_YCBCR_ENC 406 | V4L2_FMT_FLAG_CSC_QUANTIZATION | V4L2_FMT_FLAG_CSC_XFER_FUNC; 407 408 return 0; 409 } 410 411 static const struct mxc_isi_format_info * 412 __mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx *ctx, 413 struct v4l2_pix_format_mplane *pix, 414 const enum mxc_isi_video_type type) 415 { 416 if (type == MXC_ISI_VIDEO_M2M_CAP) { 417 /* Downscaling only */ 418 pix->width = min(pix->width, ctx->queues.out.format.width); 419 pix->height = min(pix->height, ctx->queues.out.format.height); 420 } 421 422 return mxc_isi_format_try(ctx->m2m->pipe, pix, type); 423 } 424 425 static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh, 426 struct v4l2_format *f) 427 { 428 const enum mxc_isi_video_type type = 429 f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? 430 MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; 431 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); 432 433 __mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type); 434 435 return 0; 436 } 437 438 static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh, 439 struct v4l2_format *f) 440 { 441 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); 442 const struct mxc_isi_m2m_ctx_queue_data *qdata = 443 mxc_isi_m2m_ctx_qdata(ctx, f->type); 444 445 f->fmt.pix_mp = qdata->format; 446 447 return 0; 448 } 449 450 static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh, 451 struct v4l2_format *f) 452 { 453 const enum mxc_isi_video_type type = 454 f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? 455 MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; 456 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); 457 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; 458 const struct mxc_isi_format_info *info; 459 struct vb2_queue *vq; 460 461 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 462 if (!vq) 463 return -EINVAL; 464 465 if (vb2_is_busy(vq)) 466 return -EBUSY; 467 468 info = __mxc_isi_m2m_try_fmt_vid(ctx, pix, type); 469 470 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 471 ctx->queues.out.format = *pix; 472 ctx->queues.out.info = info; 473 } 474 475 /* 476 * Always set the format on the capture side, due to either format 477 * propagation or direct setting. 478 */ 479 ctx->queues.cap.format = *pix; 480 ctx->queues.cap.info = info; 481 482 return 0; 483 } 484 485 static int mxc_isi_m2m_streamon(struct file *file, void *fh, 486 enum v4l2_buf_type type) 487 { 488 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); 489 const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format; 490 const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format; 491 const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info; 492 const struct mxc_isi_format_info *out_info = ctx->queues.out.info; 493 struct mxc_isi_m2m *m2m = ctx->m2m; 494 bool bypass; 495 496 int ret; 497 498 mutex_lock(&m2m->lock); 499 500 if (m2m->usage_count == INT_MAX) { 501 ret = -EOVERFLOW; 502 goto unlock; 503 } 504 505 bypass = cap_pix->width == out_pix->width && 506 cap_pix->height == out_pix->height && 507 cap_info->encoding == out_info->encoding; 508 509 /* 510 * Acquire the pipe and initialize the channel with the first user of 511 * the M2M device. 512 */ 513 if (m2m->usage_count == 0) { 514 ret = mxc_isi_channel_acquire(m2m->pipe, 515 &mxc_isi_m2m_frame_write_done, 516 bypass); 517 if (ret) 518 goto unlock; 519 520 mxc_isi_channel_get(m2m->pipe); 521 } 522 523 m2m->usage_count++; 524 525 /* 526 * Allocate resources for the channel, counting how many users require 527 * buffer chaining. 528 */ 529 if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) { 530 ret = mxc_isi_channel_chain(m2m->pipe, bypass); 531 if (ret) 532 goto deinit; 533 534 m2m->chained_count++; 535 ctx->chained = true; 536 } 537 538 /* 539 * Drop the lock to start the stream, as the .device_run() operation 540 * needs to acquire it. 541 */ 542 mutex_unlock(&m2m->lock); 543 ret = v4l2_m2m_ioctl_streamon(file, fh, type); 544 if (ret) { 545 /* Reacquire the lock for the cleanup path. */ 546 mutex_lock(&m2m->lock); 547 goto unchain; 548 } 549 550 return 0; 551 552 unchain: 553 if (ctx->chained && --m2m->chained_count == 0) 554 mxc_isi_channel_unchain(m2m->pipe); 555 ctx->chained = false; 556 557 deinit: 558 if (--m2m->usage_count == 0) { 559 mxc_isi_channel_put(m2m->pipe); 560 mxc_isi_channel_release(m2m->pipe); 561 } 562 563 unlock: 564 mutex_unlock(&m2m->lock); 565 return ret; 566 } 567 568 static int mxc_isi_m2m_streamoff(struct file *file, void *fh, 569 enum v4l2_buf_type type) 570 { 571 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); 572 struct mxc_isi_m2m *m2m = ctx->m2m; 573 574 v4l2_m2m_ioctl_streamoff(file, fh, type); 575 576 mutex_lock(&m2m->lock); 577 578 /* 579 * If the last context is this one, reset it to make sure the device 580 * will be reconfigured when streaming is restarted. 581 */ 582 if (m2m->last_ctx == ctx) 583 m2m->last_ctx = NULL; 584 585 /* Free the channel resources if this is the last chained context. */ 586 if (ctx->chained && --m2m->chained_count == 0) 587 mxc_isi_channel_unchain(m2m->pipe); 588 ctx->chained = false; 589 590 /* Turn off the light with the last user. */ 591 if (--m2m->usage_count == 0) { 592 mxc_isi_channel_disable(m2m->pipe); 593 mxc_isi_channel_put(m2m->pipe); 594 mxc_isi_channel_release(m2m->pipe); 595 } 596 597 WARN_ON(m2m->usage_count < 0); 598 599 mutex_unlock(&m2m->lock); 600 601 return 0; 602 } 603 604 static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = { 605 .vidioc_querycap = mxc_isi_m2m_querycap, 606 607 .vidioc_enum_fmt_vid_cap = mxc_isi_m2m_enum_fmt_vid, 608 .vidioc_enum_fmt_vid_out = mxc_isi_m2m_enum_fmt_vid, 609 .vidioc_g_fmt_vid_cap_mplane = mxc_isi_m2m_g_fmt_vid, 610 .vidioc_g_fmt_vid_out_mplane = mxc_isi_m2m_g_fmt_vid, 611 .vidioc_s_fmt_vid_cap_mplane = mxc_isi_m2m_s_fmt_vid, 612 .vidioc_s_fmt_vid_out_mplane = mxc_isi_m2m_s_fmt_vid, 613 .vidioc_try_fmt_vid_cap_mplane = mxc_isi_m2m_try_fmt_vid, 614 .vidioc_try_fmt_vid_out_mplane = mxc_isi_m2m_try_fmt_vid, 615 616 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 617 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 618 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 619 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 620 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 621 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 622 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 623 624 .vidioc_streamon = mxc_isi_m2m_streamon, 625 .vidioc_streamoff = mxc_isi_m2m_streamoff, 626 627 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 628 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 629 }; 630 631 /* ----------------------------------------------------------------------------- 632 * Video device file operations 633 */ 634 635 static void mxc_isi_m2m_init_format(struct mxc_isi_m2m_ctx *ctx, 636 struct mxc_isi_m2m_ctx_queue_data *qdata, 637 enum mxc_isi_video_type type) 638 { 639 qdata->format.width = MXC_ISI_DEF_WIDTH; 640 qdata->format.height = MXC_ISI_DEF_HEIGHT; 641 qdata->format.pixelformat = MXC_ISI_DEF_PIXEL_FORMAT; 642 643 qdata->info = mxc_isi_format_try(ctx->m2m->pipe, &qdata->format, type); 644 } 645 646 static int mxc_isi_m2m_open(struct file *file) 647 { 648 struct video_device *vdev = video_devdata(file); 649 struct mxc_isi_m2m *m2m = video_drvdata(file); 650 struct mxc_isi_m2m_ctx *ctx; 651 int ret; 652 653 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 654 if (!ctx) 655 return -ENOMEM; 656 657 ctx->m2m = m2m; 658 mutex_init(&ctx->vb2_lock); 659 660 v4l2_fh_init(&ctx->fh, vdev); 661 file->private_data = &ctx->fh; 662 663 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx, 664 &mxc_isi_m2m_queue_init); 665 if (IS_ERR(ctx->fh.m2m_ctx)) { 666 ret = PTR_ERR(ctx->fh.m2m_ctx); 667 ctx->fh.m2m_ctx = NULL; 668 goto err_fh; 669 } 670 671 mxc_isi_m2m_init_format(ctx, &ctx->queues.out, MXC_ISI_VIDEO_M2M_OUT); 672 mxc_isi_m2m_init_format(ctx, &ctx->queues.cap, MXC_ISI_VIDEO_M2M_CAP); 673 674 ret = mxc_isi_m2m_ctx_ctrls_create(ctx); 675 if (ret) 676 goto err_ctx; 677 678 ret = pm_runtime_resume_and_get(m2m->isi->dev); 679 if (ret) 680 goto err_ctrls; 681 682 v4l2_fh_add(&ctx->fh); 683 684 return 0; 685 686 err_ctrls: 687 mxc_isi_m2m_ctx_ctrls_delete(ctx); 688 err_ctx: 689 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 690 err_fh: 691 v4l2_fh_exit(&ctx->fh); 692 mutex_destroy(&ctx->vb2_lock); 693 kfree(ctx); 694 return ret; 695 } 696 697 static int mxc_isi_m2m_release(struct file *file) 698 { 699 struct mxc_isi_m2m *m2m = video_drvdata(file); 700 struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data); 701 702 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 703 mxc_isi_m2m_ctx_ctrls_delete(ctx); 704 705 v4l2_fh_del(&ctx->fh); 706 v4l2_fh_exit(&ctx->fh); 707 708 mutex_destroy(&ctx->vb2_lock); 709 kfree(ctx); 710 711 pm_runtime_put(m2m->isi->dev); 712 713 return 0; 714 } 715 716 static const struct v4l2_file_operations mxc_isi_m2m_fops = { 717 .owner = THIS_MODULE, 718 .open = mxc_isi_m2m_open, 719 .release = mxc_isi_m2m_release, 720 .poll = v4l2_m2m_fop_poll, 721 .unlocked_ioctl = video_ioctl2, 722 .mmap = v4l2_m2m_fop_mmap, 723 }; 724 725 /* ----------------------------------------------------------------------------- 726 * Registration 727 */ 728 729 int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev) 730 { 731 struct mxc_isi_m2m *m2m = &isi->m2m; 732 struct video_device *vdev = &m2m->vdev; 733 struct media_link *link; 734 int ret; 735 736 m2m->isi = isi; 737 m2m->pipe = &isi->pipes[0]; 738 739 mutex_init(&m2m->lock); 740 741 /* Initialize the video device and create controls. */ 742 snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.m2m"); 743 744 vdev->fops = &mxc_isi_m2m_fops; 745 vdev->ioctl_ops = &mxc_isi_m2m_ioctl_ops; 746 vdev->v4l2_dev = v4l2_dev; 747 vdev->minor = -1; 748 vdev->release = video_device_release_empty; 749 vdev->vfl_dir = VFL_DIR_M2M; 750 751 vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; 752 video_set_drvdata(vdev, m2m); 753 754 /* Create the M2M device. */ 755 m2m->m2m_dev = v4l2_m2m_init(&mxc_isi_m2m_ops); 756 if (IS_ERR(m2m->m2m_dev)) { 757 dev_err(isi->dev, "failed to initialize m2m device\n"); 758 ret = PTR_ERR(m2m->m2m_dev); 759 goto err_mutex; 760 } 761 762 /* Register the video device. */ 763 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 764 if (ret < 0) { 765 dev_err(isi->dev, "failed to register m2m device\n"); 766 goto err_m2m; 767 } 768 769 /* 770 * Populate the media graph. We can't use the mem2mem helper 771 * v4l2_m2m_register_media_controller() as the M2M interface needs to 772 * be connected to the existing entities in the graph, so we have to 773 * wire things up manually: 774 * 775 * - The entity in the video_device, which isn't touched by the V4L2 776 * core for M2M devices, is used as the source I/O entity in the 777 * graph, connected to the crossbar switch. 778 * 779 * - The video device at the end of the pipeline provides the sink 780 * entity, and is already wired up in the graph. 781 * 782 * - A new interface is created, pointing at both entities. The sink 783 * entity will thus have two interfaces pointing to it. 784 */ 785 m2m->pad.flags = MEDIA_PAD_FL_SOURCE; 786 vdev->entity.name = "mxc_isi.output"; 787 vdev->entity.function = MEDIA_ENT_F_IO_V4L; 788 ret = media_entity_pads_init(&vdev->entity, 1, &m2m->pad); 789 if (ret) 790 goto err_video; 791 792 ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity); 793 if (ret) 794 goto err_entity_cleanup; 795 796 ret = media_create_pad_link(&vdev->entity, 0, 797 &m2m->isi->crossbar.sd.entity, 798 m2m->isi->crossbar.num_sinks - 1, 799 MEDIA_LNK_FL_IMMUTABLE | 800 MEDIA_LNK_FL_ENABLED); 801 if (ret) 802 goto err_entity_unreg; 803 804 m2m->intf = media_devnode_create(v4l2_dev->mdev, MEDIA_INTF_T_V4L_VIDEO, 805 0, VIDEO_MAJOR, vdev->minor); 806 if (!m2m->intf) { 807 ret = -ENOMEM; 808 goto err_entity_unreg; 809 } 810 811 link = media_create_intf_link(&vdev->entity, &m2m->intf->intf, 812 MEDIA_LNK_FL_IMMUTABLE | 813 MEDIA_LNK_FL_ENABLED); 814 if (!link) { 815 ret = -ENOMEM; 816 goto err_devnode; 817 } 818 819 link = media_create_intf_link(&m2m->pipe->video.vdev.entity, 820 &m2m->intf->intf, 821 MEDIA_LNK_FL_IMMUTABLE | 822 MEDIA_LNK_FL_ENABLED); 823 if (!link) { 824 ret = -ENOMEM; 825 goto err_devnode; 826 } 827 828 return 0; 829 830 err_devnode: 831 media_devnode_remove(m2m->intf); 832 err_entity_unreg: 833 media_device_unregister_entity(&vdev->entity); 834 err_entity_cleanup: 835 media_entity_cleanup(&vdev->entity); 836 err_video: 837 video_unregister_device(vdev); 838 err_m2m: 839 v4l2_m2m_release(m2m->m2m_dev); 840 err_mutex: 841 mutex_destroy(&m2m->lock); 842 return ret; 843 } 844 845 int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi) 846 { 847 struct mxc_isi_m2m *m2m = &isi->m2m; 848 struct video_device *vdev = &m2m->vdev; 849 850 video_unregister_device(vdev); 851 852 v4l2_m2m_release(m2m->m2m_dev); 853 media_devnode_remove(m2m->intf); 854 media_entity_cleanup(&vdev->entity); 855 mutex_destroy(&m2m->lock); 856 857 return 0; 858 } 859