1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * i.MX IPUv3 IC PP mem2mem CSC/Scaler driver 4 * 5 * Copyright (C) 2011 Pengutronix, Sascha Hauer 6 * Copyright (C) 2018 Pengutronix, Philipp Zabel 7 */ 8 #include <linux/module.h> 9 #include <linux/delay.h> 10 #include <linux/fs.h> 11 #include <linux/sched.h> 12 #include <linux/slab.h> 13 #include <video/imx-ipu-v3.h> 14 #include <video/imx-ipu-image-convert.h> 15 16 #include <media/media-device.h> 17 #include <media/v4l2-ctrls.h> 18 #include <media/v4l2-event.h> 19 #include <media/v4l2-mem2mem.h> 20 #include <media/v4l2-device.h> 21 #include <media/v4l2-ioctl.h> 22 #include <media/videobuf2-dma-contig.h> 23 24 #include "imx-media.h" 25 26 #define fh_to_ctx(__fh) container_of(__fh, struct ipu_csc_scaler_ctx, fh) 27 28 enum { 29 V4L2_M2M_SRC = 0, 30 V4L2_M2M_DST = 1, 31 }; 32 33 struct ipu_csc_scaler_priv { 34 struct imx_media_video_dev vdev; 35 36 struct v4l2_m2m_dev *m2m_dev; 37 struct device *dev; 38 39 struct imx_media_dev *md; 40 41 struct mutex mutex; /* mem2mem device mutex */ 42 }; 43 44 #define vdev_to_priv(v) container_of(v, struct ipu_csc_scaler_priv, vdev) 45 46 /* Per-queue, driver-specific private data */ 47 struct ipu_csc_scaler_q_data { 48 struct v4l2_pix_format cur_fmt; 49 struct v4l2_rect rect; 50 }; 51 52 struct ipu_csc_scaler_ctx { 53 struct ipu_csc_scaler_priv *priv; 54 55 struct v4l2_fh fh; 56 struct ipu_csc_scaler_q_data q_data[2]; 57 struct ipu_image_convert_ctx *icc; 58 59 struct v4l2_ctrl_handler ctrl_hdlr; 60 int rotate; 61 bool hflip; 62 bool vflip; 63 enum ipu_rotate_mode rot_mode; 64 unsigned int sequence; 65 }; 66 67 static struct ipu_csc_scaler_q_data *get_q_data(struct ipu_csc_scaler_ctx *ctx, 68 enum v4l2_buf_type type) 69 { 70 if (V4L2_TYPE_IS_OUTPUT(type)) 71 return &ctx->q_data[V4L2_M2M_SRC]; 72 else 73 return &ctx->q_data[V4L2_M2M_DST]; 74 } 75 76 /* 77 * mem2mem callbacks 78 */ 79 80 static void job_abort(void *_ctx) 81 { 82 struct ipu_csc_scaler_ctx *ctx = _ctx; 83 84 if (ctx->icc) 85 ipu_image_convert_abort(ctx->icc); 86 } 87 88 static void ipu_ic_pp_complete(struct ipu_image_convert_run *run, void *_ctx) 89 { 90 struct ipu_csc_scaler_ctx *ctx = _ctx; 91 struct ipu_csc_scaler_priv *priv = ctx->priv; 92 struct vb2_v4l2_buffer *src_buf, *dst_buf; 93 94 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 95 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 96 97 v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); 98 99 src_buf->sequence = ctx->sequence++; 100 dst_buf->sequence = src_buf->sequence; 101 102 v4l2_m2m_buf_done(src_buf, run->status ? VB2_BUF_STATE_ERROR : 103 VB2_BUF_STATE_DONE); 104 v4l2_m2m_buf_done(dst_buf, run->status ? VB2_BUF_STATE_ERROR : 105 VB2_BUF_STATE_DONE); 106 107 v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx); 108 kfree(run); 109 } 110 111 static void device_run(void *_ctx) 112 { 113 struct ipu_csc_scaler_ctx *ctx = _ctx; 114 struct ipu_csc_scaler_priv *priv = ctx->priv; 115 struct vb2_v4l2_buffer *src_buf, *dst_buf; 116 struct ipu_image_convert_run *run; 117 int ret; 118 119 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 120 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 121 122 run = kzalloc(sizeof(*run), GFP_KERNEL); 123 if (!run) 124 goto err; 125 126 run->ctx = ctx->icc; 127 run->in_phys = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); 128 run->out_phys = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); 129 130 ret = ipu_image_convert_queue(run); 131 if (ret < 0) { 132 v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, 133 "%s: failed to queue: %d\n", __func__, ret); 134 goto err; 135 } 136 137 return; 138 139 err: 140 v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 141 v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 142 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); 143 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); 144 v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx); 145 } 146 147 /* 148 * Video ioctls 149 */ 150 static int ipu_csc_scaler_querycap(struct file *file, void *priv, 151 struct v4l2_capability *cap) 152 { 153 strscpy(cap->driver, "imx-media-csc-scaler", sizeof(cap->driver)); 154 strscpy(cap->card, "imx-media-csc-scaler", sizeof(cap->card)); 155 strscpy(cap->bus_info, "platform:imx-media-csc-scaler", 156 sizeof(cap->bus_info)); 157 158 return 0; 159 } 160 161 static int ipu_csc_scaler_enum_fmt(struct file *file, void *fh, 162 struct v4l2_fmtdesc *f) 163 { 164 u32 fourcc; 165 int ret; 166 167 ret = imx_media_enum_format(&fourcc, f->index, CS_SEL_ANY); 168 if (ret) 169 return ret; 170 171 f->pixelformat = fourcc; 172 173 return 0; 174 } 175 176 static int ipu_csc_scaler_g_fmt(struct file *file, void *priv, 177 struct v4l2_format *f) 178 { 179 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); 180 struct ipu_csc_scaler_q_data *q_data; 181 182 q_data = get_q_data(ctx, f->type); 183 184 f->fmt.pix = q_data->cur_fmt; 185 186 return 0; 187 } 188 189 static int ipu_csc_scaler_try_fmt(struct file *file, void *priv, 190 struct v4l2_format *f) 191 { 192 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); 193 struct ipu_csc_scaler_q_data *q_data = get_q_data(ctx, f->type); 194 struct ipu_image test_in, test_out; 195 enum v4l2_field field; 196 197 field = f->fmt.pix.field; 198 if (field == V4L2_FIELD_ANY) 199 field = V4L2_FIELD_NONE; 200 else if (field != V4L2_FIELD_NONE) 201 return -EINVAL; 202 203 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 204 struct ipu_csc_scaler_q_data *q_data_in = 205 get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 206 207 test_out.pix = f->fmt.pix; 208 test_in.pix = q_data_in->cur_fmt; 209 } else { 210 struct ipu_csc_scaler_q_data *q_data_out = 211 get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 212 213 test_in.pix = f->fmt.pix; 214 test_out.pix = q_data_out->cur_fmt; 215 } 216 217 ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode); 218 219 f->fmt.pix = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? 220 test_out.pix : test_in.pix; 221 222 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 223 f->fmt.pix.colorspace = q_data->cur_fmt.colorspace; 224 f->fmt.pix.ycbcr_enc = q_data->cur_fmt.ycbcr_enc; 225 f->fmt.pix.xfer_func = q_data->cur_fmt.xfer_func; 226 f->fmt.pix.quantization = q_data->cur_fmt.quantization; 227 } else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) { 228 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; 229 f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 230 f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; 231 f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; 232 } 233 234 return 0; 235 } 236 237 static int ipu_csc_scaler_s_fmt(struct file *file, void *priv, 238 struct v4l2_format *f) 239 { 240 struct ipu_csc_scaler_q_data *q_data; 241 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); 242 struct vb2_queue *vq; 243 int ret; 244 245 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 246 if (vb2_is_busy(vq)) { 247 v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: queue busy\n", 248 __func__); 249 return -EBUSY; 250 } 251 252 q_data = get_q_data(ctx, f->type); 253 254 ret = ipu_csc_scaler_try_fmt(file, priv, f); 255 if (ret < 0) 256 return ret; 257 258 q_data->cur_fmt.width = f->fmt.pix.width; 259 q_data->cur_fmt.height = f->fmt.pix.height; 260 q_data->cur_fmt.pixelformat = f->fmt.pix.pixelformat; 261 q_data->cur_fmt.field = f->fmt.pix.field; 262 q_data->cur_fmt.bytesperline = f->fmt.pix.bytesperline; 263 q_data->cur_fmt.sizeimage = f->fmt.pix.sizeimage; 264 265 /* Reset cropping/composing rectangle */ 266 q_data->rect.left = 0; 267 q_data->rect.top = 0; 268 q_data->rect.width = q_data->cur_fmt.width; 269 q_data->rect.height = q_data->cur_fmt.height; 270 271 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 272 /* Set colorimetry on the output queue */ 273 q_data->cur_fmt.colorspace = f->fmt.pix.colorspace; 274 q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; 275 q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func; 276 q_data->cur_fmt.quantization = f->fmt.pix.quantization; 277 /* Propagate colorimetry to the capture queue */ 278 q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 279 q_data->cur_fmt.colorspace = f->fmt.pix.colorspace; 280 q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; 281 q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func; 282 q_data->cur_fmt.quantization = f->fmt.pix.quantization; 283 } 284 285 /* 286 * TODO: Setting colorimetry on the capture queue is currently not 287 * supported by the V4L2 API 288 */ 289 290 return 0; 291 } 292 293 static int ipu_csc_scaler_g_selection(struct file *file, void *priv, 294 struct v4l2_selection *s) 295 { 296 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); 297 struct ipu_csc_scaler_q_data *q_data; 298 299 switch (s->target) { 300 case V4L2_SEL_TGT_CROP: 301 case V4L2_SEL_TGT_CROP_DEFAULT: 302 case V4L2_SEL_TGT_CROP_BOUNDS: 303 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 304 return -EINVAL; 305 q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 306 break; 307 case V4L2_SEL_TGT_COMPOSE: 308 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 309 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 310 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 311 return -EINVAL; 312 q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 313 break; 314 default: 315 return -EINVAL; 316 } 317 318 if (s->target == V4L2_SEL_TGT_CROP || 319 s->target == V4L2_SEL_TGT_COMPOSE) { 320 s->r = q_data->rect; 321 } else { 322 s->r.left = 0; 323 s->r.top = 0; 324 s->r.width = q_data->cur_fmt.width; 325 s->r.height = q_data->cur_fmt.height; 326 } 327 328 return 0; 329 } 330 331 static int ipu_csc_scaler_s_selection(struct file *file, void *priv, 332 struct v4l2_selection *s) 333 { 334 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); 335 struct ipu_csc_scaler_q_data *q_data; 336 337 switch (s->target) { 338 case V4L2_SEL_TGT_CROP: 339 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 340 return -EINVAL; 341 break; 342 case V4L2_SEL_TGT_COMPOSE: 343 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 344 return -EINVAL; 345 break; 346 default: 347 return -EINVAL; 348 } 349 350 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 351 s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 352 return -EINVAL; 353 354 q_data = get_q_data(ctx, s->type); 355 356 /* The input's frame width to the IC must be a multiple of 8 pixels 357 * When performing resizing the frame width must be multiple of burst 358 * size - 8 or 16 pixels as defined by CB#_BURST_16 parameter. 359 */ 360 if (s->flags & V4L2_SEL_FLAG_GE) 361 s->r.width = round_up(s->r.width, 8); 362 if (s->flags & V4L2_SEL_FLAG_LE) 363 s->r.width = round_down(s->r.width, 8); 364 s->r.width = clamp_t(unsigned int, s->r.width, 8, 365 round_down(q_data->cur_fmt.width, 8)); 366 s->r.height = clamp_t(unsigned int, s->r.height, 1, 367 q_data->cur_fmt.height); 368 s->r.left = clamp_t(unsigned int, s->r.left, 0, 369 q_data->cur_fmt.width - s->r.width); 370 s->r.top = clamp_t(unsigned int, s->r.top, 0, 371 q_data->cur_fmt.height - s->r.height); 372 373 /* V4L2_SEL_FLAG_KEEP_CONFIG is only valid for subdevices */ 374 q_data->rect = s->r; 375 376 return 0; 377 } 378 379 static const struct v4l2_ioctl_ops ipu_csc_scaler_ioctl_ops = { 380 .vidioc_querycap = ipu_csc_scaler_querycap, 381 382 .vidioc_enum_fmt_vid_cap = ipu_csc_scaler_enum_fmt, 383 .vidioc_g_fmt_vid_cap = ipu_csc_scaler_g_fmt, 384 .vidioc_try_fmt_vid_cap = ipu_csc_scaler_try_fmt, 385 .vidioc_s_fmt_vid_cap = ipu_csc_scaler_s_fmt, 386 387 .vidioc_enum_fmt_vid_out = ipu_csc_scaler_enum_fmt, 388 .vidioc_g_fmt_vid_out = ipu_csc_scaler_g_fmt, 389 .vidioc_try_fmt_vid_out = ipu_csc_scaler_try_fmt, 390 .vidioc_s_fmt_vid_out = ipu_csc_scaler_s_fmt, 391 392 .vidioc_g_selection = ipu_csc_scaler_g_selection, 393 .vidioc_s_selection = ipu_csc_scaler_s_selection, 394 395 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 396 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 397 398 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 399 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 400 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 401 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 402 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 403 404 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 405 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 406 407 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 408 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 409 }; 410 411 /* 412 * Queue operations 413 */ 414 415 static int ipu_csc_scaler_queue_setup(struct vb2_queue *vq, 416 unsigned int *nbuffers, 417 unsigned int *nplanes, 418 unsigned int sizes[], 419 struct device *alloc_devs[]) 420 { 421 struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq); 422 struct ipu_csc_scaler_q_data *q_data; 423 unsigned int size, count = *nbuffers; 424 425 q_data = get_q_data(ctx, vq->type); 426 427 size = q_data->cur_fmt.sizeimage; 428 429 *nbuffers = count; 430 431 if (*nplanes) 432 return sizes[0] < size ? -EINVAL : 0; 433 434 *nplanes = 1; 435 sizes[0] = size; 436 437 dev_dbg(ctx->priv->dev, "get %d buffer(s) of size %d each.\n", 438 count, size); 439 440 return 0; 441 } 442 443 static int ipu_csc_scaler_buf_prepare(struct vb2_buffer *vb) 444 { 445 struct vb2_queue *vq = vb->vb2_queue; 446 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 447 struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq); 448 struct ipu_csc_scaler_q_data *q_data; 449 unsigned long size; 450 451 dev_dbg(ctx->priv->dev, "type: %d\n", vq->type); 452 453 if (V4L2_TYPE_IS_OUTPUT(vq->type)) { 454 if (vbuf->field == V4L2_FIELD_ANY) 455 vbuf->field = V4L2_FIELD_NONE; 456 if (vbuf->field != V4L2_FIELD_NONE) { 457 dev_dbg(ctx->priv->dev, "%s: field isn't supported\n", 458 __func__); 459 return -EINVAL; 460 } 461 } 462 463 q_data = get_q_data(ctx, vq->type); 464 size = q_data->cur_fmt.sizeimage; 465 466 if (vb2_plane_size(vb, 0) < size) { 467 dev_dbg(ctx->priv->dev, 468 "%s: data will not fit into plane (%lu < %lu)\n", 469 __func__, vb2_plane_size(vb, 0), size); 470 return -EINVAL; 471 } 472 473 vb2_set_plane_payload(vb, 0, size); 474 475 return 0; 476 } 477 478 static void ipu_csc_scaler_buf_queue(struct vb2_buffer *vb) 479 { 480 struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 481 482 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb)); 483 } 484 485 static void ipu_image_from_q_data(struct ipu_image *im, 486 struct ipu_csc_scaler_q_data *q_data) 487 { 488 struct v4l2_pix_format *fmt = &q_data->cur_fmt; 489 490 im->pix = *fmt; 491 if (fmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) 492 im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 493 if (fmt->quantization == V4L2_QUANTIZATION_DEFAULT) 494 im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 495 im->rect = q_data->rect; 496 } 497 498 static int ipu_csc_scaler_start_streaming(struct vb2_queue *q, 499 unsigned int count) 500 { 501 const enum ipu_ic_task ic_task = IC_TASK_POST_PROCESSOR; 502 struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q); 503 struct ipu_csc_scaler_priv *priv = ctx->priv; 504 struct ipu_soc *ipu = priv->md->ipu[0]; 505 struct ipu_csc_scaler_q_data *q_data; 506 struct vb2_queue *other_q; 507 struct ipu_image in, out; 508 509 other_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 510 (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? 511 V4L2_BUF_TYPE_VIDEO_OUTPUT : 512 V4L2_BUF_TYPE_VIDEO_CAPTURE); 513 if (!vb2_is_streaming(other_q)) 514 return 0; 515 516 if (ctx->icc) { 517 v4l2_warn(ctx->priv->vdev.vfd->v4l2_dev, "removing old ICC\n"); 518 ipu_image_convert_unprepare(ctx->icc); 519 } 520 521 q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 522 ipu_image_from_q_data(&in, q_data); 523 524 q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 525 ipu_image_from_q_data(&out, q_data); 526 527 ctx->icc = ipu_image_convert_prepare(ipu, ic_task, &in, &out, 528 ctx->rot_mode, 529 ipu_ic_pp_complete, ctx); 530 if (IS_ERR(ctx->icc)) { 531 struct vb2_v4l2_buffer *buf; 532 int ret = PTR_ERR(ctx->icc); 533 534 ctx->icc = NULL; 535 v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: error %d\n", 536 __func__, ret); 537 while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) 538 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 539 while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) 540 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 541 return ret; 542 } 543 544 return 0; 545 } 546 547 static void ipu_csc_scaler_stop_streaming(struct vb2_queue *q) 548 { 549 struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q); 550 struct vb2_v4l2_buffer *buf; 551 552 if (ctx->icc) { 553 ipu_image_convert_unprepare(ctx->icc); 554 ctx->icc = NULL; 555 } 556 557 ctx->sequence = 0; 558 559 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 560 while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) 561 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 562 } else { 563 while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) 564 v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 565 } 566 } 567 568 static const struct vb2_ops ipu_csc_scaler_qops = { 569 .queue_setup = ipu_csc_scaler_queue_setup, 570 .buf_prepare = ipu_csc_scaler_buf_prepare, 571 .buf_queue = ipu_csc_scaler_buf_queue, 572 .wait_prepare = vb2_ops_wait_prepare, 573 .wait_finish = vb2_ops_wait_finish, 574 .start_streaming = ipu_csc_scaler_start_streaming, 575 .stop_streaming = ipu_csc_scaler_stop_streaming, 576 }; 577 578 static int ipu_csc_scaler_queue_init(void *priv, struct vb2_queue *src_vq, 579 struct vb2_queue *dst_vq) 580 { 581 struct ipu_csc_scaler_ctx *ctx = priv; 582 int ret; 583 584 memset(src_vq, 0, sizeof(*src_vq)); 585 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 586 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 587 src_vq->drv_priv = ctx; 588 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 589 src_vq->ops = &ipu_csc_scaler_qops; 590 src_vq->mem_ops = &vb2_dma_contig_memops; 591 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 592 src_vq->lock = &ctx->priv->mutex; 593 src_vq->dev = ctx->priv->dev; 594 595 ret = vb2_queue_init(src_vq); 596 if (ret) 597 return ret; 598 599 memset(dst_vq, 0, sizeof(*dst_vq)); 600 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 601 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 602 dst_vq->drv_priv = ctx; 603 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 604 dst_vq->ops = &ipu_csc_scaler_qops; 605 dst_vq->mem_ops = &vb2_dma_contig_memops; 606 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 607 dst_vq->lock = &ctx->priv->mutex; 608 dst_vq->dev = ctx->priv->dev; 609 610 return vb2_queue_init(dst_vq); 611 } 612 613 static int ipu_csc_scaler_s_ctrl(struct v4l2_ctrl *ctrl) 614 { 615 struct ipu_csc_scaler_ctx *ctx = container_of(ctrl->handler, 616 struct ipu_csc_scaler_ctx, 617 ctrl_hdlr); 618 enum ipu_rotate_mode rot_mode; 619 int rotate; 620 bool hflip, vflip; 621 int ret = 0; 622 623 rotate = ctx->rotate; 624 hflip = ctx->hflip; 625 vflip = ctx->vflip; 626 627 switch (ctrl->id) { 628 case V4L2_CID_HFLIP: 629 hflip = ctrl->val; 630 break; 631 case V4L2_CID_VFLIP: 632 vflip = ctrl->val; 633 break; 634 case V4L2_CID_ROTATE: 635 rotate = ctrl->val; 636 break; 637 default: 638 return -EINVAL; 639 } 640 641 ret = ipu_degrees_to_rot_mode(&rot_mode, rotate, hflip, vflip); 642 if (ret) 643 return ret; 644 645 if (rot_mode != ctx->rot_mode) { 646 struct v4l2_pix_format *in_fmt, *out_fmt; 647 struct ipu_image test_in, test_out; 648 649 in_fmt = &ctx->q_data[V4L2_M2M_SRC].cur_fmt; 650 out_fmt = &ctx->q_data[V4L2_M2M_DST].cur_fmt; 651 652 test_in.pix = *in_fmt; 653 test_out.pix = *out_fmt; 654 655 if (ipu_rot_mode_is_irt(rot_mode) != 656 ipu_rot_mode_is_irt(ctx->rot_mode)) { 657 /* Switch width & height to keep aspect ratio intact */ 658 test_out.pix.width = out_fmt->height; 659 test_out.pix.height = out_fmt->width; 660 } 661 662 ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode); 663 664 /* Check if output format needs to be changed */ 665 if (test_in.pix.width != in_fmt->width || 666 test_in.pix.height != in_fmt->height || 667 test_in.pix.bytesperline != in_fmt->bytesperline || 668 test_in.pix.sizeimage != in_fmt->sizeimage) { 669 struct vb2_queue *out_q; 670 671 out_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 672 V4L2_BUF_TYPE_VIDEO_OUTPUT); 673 if (vb2_is_busy(out_q)) 674 return -EBUSY; 675 } 676 677 /* Check if capture format needs to be changed */ 678 if (test_out.pix.width != out_fmt->width || 679 test_out.pix.height != out_fmt->height || 680 test_out.pix.bytesperline != out_fmt->bytesperline || 681 test_out.pix.sizeimage != out_fmt->sizeimage) { 682 struct vb2_queue *cap_q; 683 684 cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 685 V4L2_BUF_TYPE_VIDEO_CAPTURE); 686 if (vb2_is_busy(cap_q)) 687 return -EBUSY; 688 } 689 690 *in_fmt = test_in.pix; 691 *out_fmt = test_out.pix; 692 693 ctx->rot_mode = rot_mode; 694 ctx->rotate = rotate; 695 ctx->hflip = hflip; 696 ctx->vflip = vflip; 697 } 698 699 return 0; 700 } 701 702 static const struct v4l2_ctrl_ops ipu_csc_scaler_ctrl_ops = { 703 .s_ctrl = ipu_csc_scaler_s_ctrl, 704 }; 705 706 static int ipu_csc_scaler_init_controls(struct ipu_csc_scaler_ctx *ctx) 707 { 708 struct v4l2_ctrl_handler *hdlr = &ctx->ctrl_hdlr; 709 710 v4l2_ctrl_handler_init(hdlr, 3); 711 712 v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_HFLIP, 713 0, 1, 1, 0); 714 v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_VFLIP, 715 0, 1, 1, 0); 716 v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_ROTATE, 717 0, 270, 90, 0); 718 719 if (hdlr->error) { 720 v4l2_ctrl_handler_free(hdlr); 721 return hdlr->error; 722 } 723 724 v4l2_ctrl_handler_setup(hdlr); 725 return 0; 726 } 727 728 #define DEFAULT_WIDTH 720 729 #define DEFAULT_HEIGHT 576 730 static const struct ipu_csc_scaler_q_data ipu_csc_scaler_q_data_default = { 731 .cur_fmt = { 732 .width = DEFAULT_WIDTH, 733 .height = DEFAULT_HEIGHT, 734 .pixelformat = V4L2_PIX_FMT_YUV420, 735 .field = V4L2_FIELD_NONE, 736 .bytesperline = DEFAULT_WIDTH, 737 .sizeimage = DEFAULT_WIDTH * DEFAULT_HEIGHT * 3 / 2, 738 .colorspace = V4L2_COLORSPACE_SRGB, 739 }, 740 .rect = { 741 .width = DEFAULT_WIDTH, 742 .height = DEFAULT_HEIGHT, 743 }, 744 }; 745 746 /* 747 * File operations 748 */ 749 static int ipu_csc_scaler_open(struct file *file) 750 { 751 struct ipu_csc_scaler_priv *priv = video_drvdata(file); 752 struct ipu_csc_scaler_ctx *ctx = NULL; 753 int ret; 754 755 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 756 if (!ctx) 757 return -ENOMEM; 758 759 ctx->rot_mode = IPU_ROTATE_NONE; 760 761 v4l2_fh_init(&ctx->fh, video_devdata(file)); 762 file->private_data = &ctx->fh; 763 v4l2_fh_add(&ctx->fh); 764 ctx->priv = priv; 765 766 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(priv->m2m_dev, ctx, 767 &ipu_csc_scaler_queue_init); 768 if (IS_ERR(ctx->fh.m2m_ctx)) { 769 ret = PTR_ERR(ctx->fh.m2m_ctx); 770 goto err_ctx; 771 } 772 773 ret = ipu_csc_scaler_init_controls(ctx); 774 if (ret) 775 goto err_ctrls; 776 777 ctx->fh.ctrl_handler = &ctx->ctrl_hdlr; 778 779 ctx->q_data[V4L2_M2M_SRC] = ipu_csc_scaler_q_data_default; 780 ctx->q_data[V4L2_M2M_DST] = ipu_csc_scaler_q_data_default; 781 782 dev_dbg(priv->dev, "Created instance %p, m2m_ctx: %p\n", ctx, 783 ctx->fh.m2m_ctx); 784 785 return 0; 786 787 err_ctrls: 788 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 789 err_ctx: 790 v4l2_fh_del(&ctx->fh); 791 v4l2_fh_exit(&ctx->fh); 792 kfree(ctx); 793 return ret; 794 } 795 796 static int ipu_csc_scaler_release(struct file *file) 797 { 798 struct ipu_csc_scaler_priv *priv = video_drvdata(file); 799 struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(file->private_data); 800 801 dev_dbg(priv->dev, "Releasing instance %p\n", ctx); 802 803 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 804 v4l2_fh_del(&ctx->fh); 805 v4l2_fh_exit(&ctx->fh); 806 kfree(ctx); 807 808 return 0; 809 } 810 811 static const struct v4l2_file_operations ipu_csc_scaler_fops = { 812 .owner = THIS_MODULE, 813 .open = ipu_csc_scaler_open, 814 .release = ipu_csc_scaler_release, 815 .poll = v4l2_m2m_fop_poll, 816 .unlocked_ioctl = video_ioctl2, 817 .mmap = v4l2_m2m_fop_mmap, 818 }; 819 820 static struct v4l2_m2m_ops m2m_ops = { 821 .device_run = device_run, 822 .job_abort = job_abort, 823 }; 824 825 static void ipu_csc_scaler_video_device_release(struct video_device *vdev) 826 { 827 struct ipu_csc_scaler_priv *priv = video_get_drvdata(vdev); 828 829 v4l2_m2m_release(priv->m2m_dev); 830 video_device_release(vdev); 831 kfree(priv); 832 } 833 834 static const struct video_device ipu_csc_scaler_videodev_template = { 835 .name = "ipu_ic_pp csc/scaler", 836 .fops = &ipu_csc_scaler_fops, 837 .ioctl_ops = &ipu_csc_scaler_ioctl_ops, 838 .minor = -1, 839 .release = ipu_csc_scaler_video_device_release, 840 .vfl_dir = VFL_DIR_M2M, 841 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, 842 }; 843 844 int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev) 845 { 846 struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev); 847 struct video_device *vfd = vdev->vfd; 848 int ret; 849 850 vfd->v4l2_dev = &priv->md->v4l2_dev; 851 852 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); 853 if (ret) { 854 v4l2_err(vfd->v4l2_dev, "Failed to register video device\n"); 855 return ret; 856 } 857 858 v4l2_info(vfd->v4l2_dev, "Registered %s as /dev/%s\n", vfd->name, 859 video_device_node_name(vfd)); 860 861 return 0; 862 } 863 864 void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev) 865 { 866 struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev); 867 struct video_device *vfd = priv->vdev.vfd; 868 869 mutex_lock(&priv->mutex); 870 871 video_unregister_device(vfd); 872 873 mutex_unlock(&priv->mutex); 874 } 875 876 struct imx_media_video_dev * 877 imx_media_csc_scaler_device_init(struct imx_media_dev *md) 878 { 879 struct ipu_csc_scaler_priv *priv; 880 struct video_device *vfd; 881 int ret; 882 883 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 884 if (!priv) 885 return ERR_PTR(-ENOMEM); 886 887 priv->md = md; 888 priv->dev = md->md.dev; 889 890 mutex_init(&priv->mutex); 891 892 vfd = video_device_alloc(); 893 if (!vfd) { 894 ret = -ENOMEM; 895 goto err_vfd; 896 } 897 898 *vfd = ipu_csc_scaler_videodev_template; 899 vfd->lock = &priv->mutex; 900 priv->vdev.vfd = vfd; 901 902 INIT_LIST_HEAD(&priv->vdev.list); 903 904 video_set_drvdata(vfd, priv); 905 906 priv->m2m_dev = v4l2_m2m_init(&m2m_ops); 907 if (IS_ERR(priv->m2m_dev)) { 908 ret = PTR_ERR(priv->m2m_dev); 909 v4l2_err(&md->v4l2_dev, "Failed to init mem2mem device: %d\n", 910 ret); 911 goto err_m2m; 912 } 913 914 return &priv->vdev; 915 916 err_m2m: 917 video_set_drvdata(vfd, NULL); 918 err_vfd: 919 kfree(priv); 920 return ERR_PTR(ret); 921 } 922 923 MODULE_DESCRIPTION("i.MX IPUv3 mem2mem scaler/CSC driver"); 924 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 925 MODULE_LICENSE("GPL"); 926