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