root/drivers/staging/media/sunxi/cedrus/cedrus_video.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cedrus_file2ctx
  2. cedrus_find_format
  3. cedrus_check_format
  4. cedrus_prepare_format
  5. cedrus_querycap
  6. cedrus_enum_fmt
  7. cedrus_enum_fmt_vid_cap
  8. cedrus_enum_fmt_vid_out
  9. cedrus_g_fmt_vid_cap
  10. cedrus_g_fmt_vid_out
  11. cedrus_try_fmt_vid_cap
  12. cedrus_try_fmt_vid_out
  13. cedrus_s_fmt_vid_cap
  14. cedrus_s_fmt_vid_out
  15. cedrus_queue_setup
  16. cedrus_queue_cleanup
  17. cedrus_buf_out_validate
  18. cedrus_buf_prepare
  19. cedrus_start_streaming
  20. cedrus_stop_streaming
  21. cedrus_buf_queue
  22. cedrus_buf_request_complete
  23. cedrus_queue_init

   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 }

/* [<][>][^][v][top][bottom][index][help] */