1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cedrus VPU driver 4 * 5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com> 6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com> 7 * Copyright (C) 2018 Bootlin 8 * 9 * Based on the vim2m driver, that is: 10 * 11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. 12 * Pawel Osciak, <pawel@osciak.com> 13 * Marek Szyprowski, <m.szyprowski@samsung.com> 14 */ 15 16 #include <media/videobuf2-dma-contig.h> 17 #include <media/v4l2-device.h> 18 #include <media/v4l2-ioctl.h> 19 #include <media/v4l2-event.h> 20 #include <media/v4l2-mem2mem.h> 21 22 #include "cedrus.h" 23 #include "cedrus_video.h" 24 #include "cedrus_dec.h" 25 #include "cedrus_hw.h" 26 27 #define CEDRUS_DECODE_SRC BIT(0) 28 #define CEDRUS_DECODE_DST BIT(1) 29 30 #define CEDRUS_MIN_WIDTH 16U 31 #define CEDRUS_MIN_HEIGHT 16U 32 #define CEDRUS_MAX_WIDTH 3840U 33 #define CEDRUS_MAX_HEIGHT 2160U 34 35 static struct cedrus_format cedrus_formats[] = { 36 { 37 .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE, 38 .directions = CEDRUS_DECODE_SRC, 39 }, 40 { 41 .pixelformat = V4L2_PIX_FMT_H264_SLICE, 42 .directions = CEDRUS_DECODE_SRC, 43 }, 44 { 45 .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, 46 .directions = CEDRUS_DECODE_DST, 47 }, 48 { 49 .pixelformat = V4L2_PIX_FMT_NV12, 50 .directions = CEDRUS_DECODE_DST, 51 .capabilities = CEDRUS_CAPABILITY_UNTILED, 52 }, 53 }; 54 55 #define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats) 56 57 static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file) 58 { 59 return container_of(file->private_data, struct cedrus_ctx, fh); 60 } 61 62 static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions, 63 unsigned int capabilities) 64 { 65 struct cedrus_format *fmt; 66 unsigned int i; 67 68 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) { 69 fmt = &cedrus_formats[i]; 70 71 if (fmt->capabilities && (fmt->capabilities & capabilities) != 72 fmt->capabilities) 73 continue; 74 75 if (fmt->pixelformat == pixelformat && 76 (fmt->directions & directions) != 0) 77 break; 78 } 79 80 if (i == CEDRUS_FORMATS_COUNT) 81 return NULL; 82 83 return &cedrus_formats[i]; 84 } 85 86 static bool cedrus_check_format(u32 pixelformat, u32 directions, 87 unsigned int capabilities) 88 { 89 return cedrus_find_format(pixelformat, directions, capabilities); 90 } 91 92 static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) 93 { 94 unsigned int width = pix_fmt->width; 95 unsigned int height = pix_fmt->height; 96 unsigned int sizeimage = pix_fmt->sizeimage; 97 unsigned int bytesperline = pix_fmt->bytesperline; 98 99 pix_fmt->field = V4L2_FIELD_NONE; 100 101 /* Limit to hardware min/max. */ 102 width = clamp(width, CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH); 103 height = clamp(height, CEDRUS_MIN_HEIGHT, CEDRUS_MAX_HEIGHT); 104 105 switch (pix_fmt->pixelformat) { 106 case V4L2_PIX_FMT_MPEG2_SLICE: 107 case V4L2_PIX_FMT_H264_SLICE: 108 /* Zero bytes per line for encoded source. */ 109 bytesperline = 0; 110 111 break; 112 113 case V4L2_PIX_FMT_SUNXI_TILED_NV12: 114 /* 32-aligned stride. */ 115 bytesperline = ALIGN(width, 32); 116 117 /* 32-aligned height. */ 118 height = ALIGN(height, 32); 119 120 /* Luma plane size. */ 121 sizeimage = bytesperline * height; 122 123 /* Chroma plane size. */ 124 sizeimage += bytesperline * height / 2; 125 126 break; 127 128 case V4L2_PIX_FMT_NV12: 129 /* 16-aligned stride. */ 130 bytesperline = ALIGN(width, 16); 131 132 /* 16-aligned height. */ 133 height = ALIGN(height, 16); 134 135 /* Luma plane size. */ 136 sizeimage = bytesperline * height; 137 138 /* Chroma plane size. */ 139 sizeimage += bytesperline * height / 2; 140 141 break; 142 } 143 144 pix_fmt->width = width; 145 pix_fmt->height = height; 146 147 pix_fmt->bytesperline = bytesperline; 148 pix_fmt->sizeimage = sizeimage; 149 } 150 151 static int cedrus_querycap(struct file *file, void *priv, 152 struct v4l2_capability *cap) 153 { 154 strscpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver)); 155 strscpy(cap->card, CEDRUS_NAME, sizeof(cap->card)); 156 snprintf(cap->bus_info, sizeof(cap->bus_info), 157 "platform:%s", CEDRUS_NAME); 158 159 return 0; 160 } 161 162 static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, 163 u32 direction) 164 { 165 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 166 struct cedrus_dev *dev = ctx->dev; 167 unsigned int capabilities = dev->capabilities; 168 struct cedrus_format *fmt; 169 unsigned int i, index; 170 171 /* Index among formats that match the requested direction. */ 172 index = 0; 173 174 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) { 175 fmt = &cedrus_formats[i]; 176 177 if (fmt->capabilities && (fmt->capabilities & capabilities) != 178 fmt->capabilities) 179 continue; 180 181 if (!(cedrus_formats[i].directions & direction)) 182 continue; 183 184 if (index == f->index) 185 break; 186 187 index++; 188 } 189 190 /* Matched format. */ 191 if (i < CEDRUS_FORMATS_COUNT) { 192 f->pixelformat = cedrus_formats[i].pixelformat; 193 194 return 0; 195 } 196 197 return -EINVAL; 198 } 199 200 static int cedrus_enum_fmt_vid_cap(struct file *file, void *priv, 201 struct v4l2_fmtdesc *f) 202 { 203 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_DST); 204 } 205 206 static int cedrus_enum_fmt_vid_out(struct file *file, void *priv, 207 struct v4l2_fmtdesc *f) 208 { 209 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_SRC); 210 } 211 212 static int cedrus_g_fmt_vid_cap(struct file *file, void *priv, 213 struct v4l2_format *f) 214 { 215 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 216 217 /* Fall back to dummy default by lack of hardware configuration. */ 218 if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { 219 f->fmt.pix.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; 220 cedrus_prepare_format(&f->fmt.pix); 221 222 return 0; 223 } 224 225 f->fmt.pix = ctx->dst_fmt; 226 227 return 0; 228 } 229 230 static int cedrus_g_fmt_vid_out(struct file *file, void *priv, 231 struct v4l2_format *f) 232 { 233 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 234 235 /* Fall back to dummy default by lack of hardware configuration. */ 236 if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { 237 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; 238 f->fmt.pix.sizeimage = SZ_1K; 239 cedrus_prepare_format(&f->fmt.pix); 240 241 return 0; 242 } 243 244 f->fmt.pix = ctx->src_fmt; 245 246 return 0; 247 } 248 249 static int cedrus_try_fmt_vid_cap(struct file *file, void *priv, 250 struct v4l2_format *f) 251 { 252 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 253 struct cedrus_dev *dev = ctx->dev; 254 struct v4l2_pix_format *pix_fmt = &f->fmt.pix; 255 256 if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, 257 dev->capabilities)) 258 return -EINVAL; 259 260 cedrus_prepare_format(pix_fmt); 261 262 return 0; 263 } 264 265 static int cedrus_try_fmt_vid_out(struct file *file, void *priv, 266 struct v4l2_format *f) 267 { 268 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 269 struct cedrus_dev *dev = ctx->dev; 270 struct v4l2_pix_format *pix_fmt = &f->fmt.pix; 271 272 if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, 273 dev->capabilities)) 274 return -EINVAL; 275 276 /* Source image size has to be provided by userspace. */ 277 if (pix_fmt->sizeimage == 0) 278 return -EINVAL; 279 280 cedrus_prepare_format(pix_fmt); 281 282 return 0; 283 } 284 285 static int cedrus_s_fmt_vid_cap(struct file *file, void *priv, 286 struct v4l2_format *f) 287 { 288 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 289 struct cedrus_dev *dev = ctx->dev; 290 struct vb2_queue *vq; 291 int ret; 292 293 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 294 if (vb2_is_busy(vq)) 295 return -EBUSY; 296 297 ret = cedrus_try_fmt_vid_cap(file, priv, f); 298 if (ret) 299 return ret; 300 301 ctx->dst_fmt = f->fmt.pix; 302 303 cedrus_dst_format_set(dev, &ctx->dst_fmt); 304 305 return 0; 306 } 307 308 static int cedrus_s_fmt_vid_out(struct file *file, void *priv, 309 struct v4l2_format *f) 310 { 311 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 312 struct vb2_queue *vq; 313 int ret; 314 315 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 316 if (vb2_is_busy(vq)) 317 return -EBUSY; 318 319 ret = cedrus_try_fmt_vid_out(file, priv, f); 320 if (ret) 321 return ret; 322 323 ctx->src_fmt = f->fmt.pix; 324 325 /* Propagate colorspace information to capture. */ 326 ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; 327 ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; 328 ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; 329 ctx->dst_fmt.quantization = f->fmt.pix.quantization; 330 331 return 0; 332 } 333 334 const struct v4l2_ioctl_ops cedrus_ioctl_ops = { 335 .vidioc_querycap = cedrus_querycap, 336 337 .vidioc_enum_fmt_vid_cap = cedrus_enum_fmt_vid_cap, 338 .vidioc_g_fmt_vid_cap = cedrus_g_fmt_vid_cap, 339 .vidioc_try_fmt_vid_cap = cedrus_try_fmt_vid_cap, 340 .vidioc_s_fmt_vid_cap = cedrus_s_fmt_vid_cap, 341 342 .vidioc_enum_fmt_vid_out = cedrus_enum_fmt_vid_out, 343 .vidioc_g_fmt_vid_out = cedrus_g_fmt_vid_out, 344 .vidioc_try_fmt_vid_out = cedrus_try_fmt_vid_out, 345 .vidioc_s_fmt_vid_out = cedrus_s_fmt_vid_out, 346 347 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 348 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 349 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 350 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 351 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 352 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 353 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 354 355 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 356 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 357 358 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 359 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 360 }; 361 362 static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, 363 unsigned int *nplanes, unsigned int sizes[], 364 struct device *alloc_devs[]) 365 { 366 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); 367 struct cedrus_dev *dev = ctx->dev; 368 struct v4l2_pix_format *pix_fmt; 369 u32 directions; 370 371 if (V4L2_TYPE_IS_OUTPUT(vq->type)) { 372 directions = CEDRUS_DECODE_SRC; 373 pix_fmt = &ctx->src_fmt; 374 } else { 375 directions = CEDRUS_DECODE_DST; 376 pix_fmt = &ctx->dst_fmt; 377 } 378 379 if (!cedrus_check_format(pix_fmt->pixelformat, directions, 380 dev->capabilities)) 381 return -EINVAL; 382 383 if (*nplanes) { 384 if (sizes[0] < pix_fmt->sizeimage) 385 return -EINVAL; 386 } else { 387 sizes[0] = pix_fmt->sizeimage; 388 *nplanes = 1; 389 } 390 391 return 0; 392 } 393 394 static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state) 395 { 396 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); 397 struct vb2_v4l2_buffer *vbuf; 398 399 for (;;) { 400 if (V4L2_TYPE_IS_OUTPUT(vq->type)) 401 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 402 else 403 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 404 405 if (!vbuf) 406 return; 407 408 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, 409 &ctx->hdl); 410 v4l2_m2m_buf_done(vbuf, state); 411 } 412 } 413 414 static int cedrus_buf_out_validate(struct vb2_buffer *vb) 415 { 416 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 417 418 vbuf->field = V4L2_FIELD_NONE; 419 return 0; 420 } 421 422 static int cedrus_buf_prepare(struct vb2_buffer *vb) 423 { 424 struct vb2_queue *vq = vb->vb2_queue; 425 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); 426 struct v4l2_pix_format *pix_fmt; 427 428 if (V4L2_TYPE_IS_OUTPUT(vq->type)) 429 pix_fmt = &ctx->src_fmt; 430 else 431 pix_fmt = &ctx->dst_fmt; 432 433 if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage) 434 return -EINVAL; 435 436 vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); 437 438 return 0; 439 } 440 441 static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) 442 { 443 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); 444 struct cedrus_dev *dev = ctx->dev; 445 int ret = 0; 446 447 switch (ctx->src_fmt.pixelformat) { 448 case V4L2_PIX_FMT_MPEG2_SLICE: 449 ctx->current_codec = CEDRUS_CODEC_MPEG2; 450 break; 451 452 case V4L2_PIX_FMT_H264_SLICE: 453 ctx->current_codec = CEDRUS_CODEC_H264; 454 break; 455 456 default: 457 return -EINVAL; 458 } 459 460 if (V4L2_TYPE_IS_OUTPUT(vq->type) && 461 dev->dec_ops[ctx->current_codec]->start) 462 ret = dev->dec_ops[ctx->current_codec]->start(ctx); 463 464 if (ret) 465 cedrus_queue_cleanup(vq, VB2_BUF_STATE_QUEUED); 466 467 return ret; 468 } 469 470 static void cedrus_stop_streaming(struct vb2_queue *vq) 471 { 472 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); 473 struct cedrus_dev *dev = ctx->dev; 474 475 if (V4L2_TYPE_IS_OUTPUT(vq->type) && 476 dev->dec_ops[ctx->current_codec]->stop) 477 dev->dec_ops[ctx->current_codec]->stop(ctx); 478 479 cedrus_queue_cleanup(vq, VB2_BUF_STATE_ERROR); 480 } 481 482 static void cedrus_buf_queue(struct vb2_buffer *vb) 483 { 484 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 485 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 486 487 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 488 } 489 490 static void cedrus_buf_request_complete(struct vb2_buffer *vb) 491 { 492 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 493 494 v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); 495 } 496 497 static struct vb2_ops cedrus_qops = { 498 .queue_setup = cedrus_queue_setup, 499 .buf_prepare = cedrus_buf_prepare, 500 .buf_queue = cedrus_buf_queue, 501 .buf_out_validate = cedrus_buf_out_validate, 502 .buf_request_complete = cedrus_buf_request_complete, 503 .start_streaming = cedrus_start_streaming, 504 .stop_streaming = cedrus_stop_streaming, 505 .wait_prepare = vb2_ops_wait_prepare, 506 .wait_finish = vb2_ops_wait_finish, 507 }; 508 509 int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, 510 struct vb2_queue *dst_vq) 511 { 512 struct cedrus_ctx *ctx = priv; 513 int ret; 514 515 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 516 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 517 src_vq->drv_priv = ctx; 518 src_vq->buf_struct_size = sizeof(struct cedrus_buffer); 519 src_vq->min_buffers_needed = 1; 520 src_vq->ops = &cedrus_qops; 521 src_vq->mem_ops = &vb2_dma_contig_memops; 522 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 523 src_vq->lock = &ctx->dev->dev_mutex; 524 src_vq->dev = ctx->dev->dev; 525 src_vq->supports_requests = true; 526 src_vq->requires_requests = true; 527 528 ret = vb2_queue_init(src_vq); 529 if (ret) 530 return ret; 531 532 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 533 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 534 dst_vq->drv_priv = ctx; 535 dst_vq->buf_struct_size = sizeof(struct cedrus_buffer); 536 dst_vq->min_buffers_needed = 1; 537 dst_vq->ops = &cedrus_qops; 538 dst_vq->mem_ops = &vb2_dma_contig_memops; 539 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 540 dst_vq->lock = &ctx->dev->dev_mutex; 541 dst_vq->dev = ctx->dev->dev; 542 543 return vb2_queue_init(dst_vq); 544 } 545