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

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

DEFINITIONS

This source file includes following definitions.
  1. cedrus_find_control_data
  2. cedrus_init_ctrls
  3. cedrus_request_validate
  4. cedrus_open
  5. cedrus_release
  6. cedrus_probe
  7. cedrus_remove

   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 <linux/platform_device.h>
  17 #include <linux/module.h>
  18 #include <linux/of.h>
  19 
  20 #include <media/v4l2-device.h>
  21 #include <media/v4l2-ioctl.h>
  22 #include <media/v4l2-ctrls.h>
  23 #include <media/v4l2-mem2mem.h>
  24 
  25 #include "cedrus.h"
  26 #include "cedrus_video.h"
  27 #include "cedrus_dec.h"
  28 #include "cedrus_hw.h"
  29 
  30 static const struct cedrus_control cedrus_controls[] = {
  31         {
  32                 .cfg = {
  33                         .id     = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
  34                 },
  35                 .codec          = CEDRUS_CODEC_MPEG2,
  36                 .required       = true,
  37         },
  38         {
  39                 .cfg = {
  40                         .id     = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
  41                 },
  42                 .codec          = CEDRUS_CODEC_MPEG2,
  43                 .required       = false,
  44         },
  45         {
  46                 .cfg = {
  47                         .id     = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
  48                 },
  49                 .codec          = CEDRUS_CODEC_H264,
  50                 .required       = true,
  51         },
  52         {
  53                 .cfg = {
  54                         .id     = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
  55                 },
  56                 .codec          = CEDRUS_CODEC_H264,
  57                 .required       = true,
  58         },
  59         {
  60                 .cfg = {
  61                         .id     = V4L2_CID_MPEG_VIDEO_H264_SPS,
  62                 },
  63                 .codec          = CEDRUS_CODEC_H264,
  64                 .required       = true,
  65         },
  66         {
  67                 .cfg = {
  68                         .id     = V4L2_CID_MPEG_VIDEO_H264_PPS,
  69                 },
  70                 .codec          = CEDRUS_CODEC_H264,
  71                 .required       = true,
  72         },
  73         {
  74                 .cfg = {
  75                         .id     = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
  76                 },
  77                 .codec          = CEDRUS_CODEC_H264,
  78                 .required       = true,
  79         },
  80         {
  81                 .cfg = {
  82                         .id     = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
  83                         .max    = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
  84                         .def    = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
  85                 },
  86                 .codec          = CEDRUS_CODEC_H264,
  87                 .required       = false,
  88         },
  89         {
  90                 .cfg = {
  91                         .id     = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
  92                         .max    = V4L2_MPEG_VIDEO_H264_START_CODE_NONE,
  93                         .def    = V4L2_MPEG_VIDEO_H264_START_CODE_NONE,
  94                 },
  95                 .codec          = CEDRUS_CODEC_H264,
  96                 .required       = false,
  97         },
  98 };
  99 
 100 #define CEDRUS_CONTROLS_COUNT   ARRAY_SIZE(cedrus_controls)
 101 
 102 void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
 103 {
 104         unsigned int i;
 105 
 106         for (i = 0; ctx->ctrls[i]; i++)
 107                 if (ctx->ctrls[i]->id == id)
 108                         return ctx->ctrls[i]->p_cur.p;
 109 
 110         return NULL;
 111 }
 112 
 113 static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
 114 {
 115         struct v4l2_ctrl_handler *hdl = &ctx->hdl;
 116         struct v4l2_ctrl *ctrl;
 117         unsigned int ctrl_size;
 118         unsigned int i;
 119 
 120         v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
 121         if (hdl->error) {
 122                 v4l2_err(&dev->v4l2_dev,
 123                          "Failed to initialize control handler\n");
 124                 return hdl->error;
 125         }
 126 
 127         ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
 128 
 129         ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
 130         if (!ctx->ctrls)
 131                 return -ENOMEM;
 132 
 133         for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
 134                 ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
 135                                             NULL);
 136                 if (hdl->error) {
 137                         v4l2_err(&dev->v4l2_dev,
 138                                  "Failed to create new custom control\n");
 139 
 140                         v4l2_ctrl_handler_free(hdl);
 141                         kfree(ctx->ctrls);
 142                         return hdl->error;
 143                 }
 144 
 145                 ctx->ctrls[i] = ctrl;
 146         }
 147 
 148         ctx->fh.ctrl_handler = hdl;
 149         v4l2_ctrl_handler_setup(hdl);
 150 
 151         return 0;
 152 }
 153 
 154 static int cedrus_request_validate(struct media_request *req)
 155 {
 156         struct media_request_object *obj;
 157         struct v4l2_ctrl_handler *parent_hdl, *hdl;
 158         struct cedrus_ctx *ctx = NULL;
 159         struct v4l2_ctrl *ctrl_test;
 160         unsigned int count;
 161         unsigned int i;
 162 
 163         list_for_each_entry(obj, &req->objects, list) {
 164                 struct vb2_buffer *vb;
 165 
 166                 if (vb2_request_object_is_buffer(obj)) {
 167                         vb = container_of(obj, struct vb2_buffer, req_obj);
 168                         ctx = vb2_get_drv_priv(vb->vb2_queue);
 169 
 170                         break;
 171                 }
 172         }
 173 
 174         if (!ctx)
 175                 return -ENOENT;
 176 
 177         count = vb2_request_buffer_cnt(req);
 178         if (!count) {
 179                 v4l2_info(&ctx->dev->v4l2_dev,
 180                           "No buffer was provided with the request\n");
 181                 return -ENOENT;
 182         } else if (count > 1) {
 183                 v4l2_info(&ctx->dev->v4l2_dev,
 184                           "More than one buffer was provided with the request\n");
 185                 return -EINVAL;
 186         }
 187 
 188         parent_hdl = &ctx->hdl;
 189 
 190         hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
 191         if (!hdl) {
 192                 v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n");
 193                 return -ENOENT;
 194         }
 195 
 196         for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
 197                 if (cedrus_controls[i].codec != ctx->current_codec ||
 198                     !cedrus_controls[i].required)
 199                         continue;
 200 
 201                 ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl,
 202                                                             cedrus_controls[i].cfg.id);
 203                 if (!ctrl_test) {
 204                         v4l2_info(&ctx->dev->v4l2_dev,
 205                                   "Missing required codec control\n");
 206                         return -ENOENT;
 207                 }
 208         }
 209 
 210         v4l2_ctrl_request_hdl_put(hdl);
 211 
 212         return vb2_request_validate(req);
 213 }
 214 
 215 static int cedrus_open(struct file *file)
 216 {
 217         struct cedrus_dev *dev = video_drvdata(file);
 218         struct cedrus_ctx *ctx = NULL;
 219         int ret;
 220 
 221         if (mutex_lock_interruptible(&dev->dev_mutex))
 222                 return -ERESTARTSYS;
 223 
 224         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 225         if (!ctx) {
 226                 mutex_unlock(&dev->dev_mutex);
 227                 return -ENOMEM;
 228         }
 229 
 230         v4l2_fh_init(&ctx->fh, video_devdata(file));
 231         file->private_data = &ctx->fh;
 232         ctx->dev = dev;
 233 
 234         ret = cedrus_init_ctrls(dev, ctx);
 235         if (ret)
 236                 goto err_free;
 237 
 238         ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
 239                                             &cedrus_queue_init);
 240         if (IS_ERR(ctx->fh.m2m_ctx)) {
 241                 ret = PTR_ERR(ctx->fh.m2m_ctx);
 242                 goto err_ctrls;
 243         }
 244 
 245         v4l2_fh_add(&ctx->fh);
 246 
 247         mutex_unlock(&dev->dev_mutex);
 248 
 249         return 0;
 250 
 251 err_ctrls:
 252         v4l2_ctrl_handler_free(&ctx->hdl);
 253 err_free:
 254         kfree(ctx);
 255         mutex_unlock(&dev->dev_mutex);
 256 
 257         return ret;
 258 }
 259 
 260 static int cedrus_release(struct file *file)
 261 {
 262         struct cedrus_dev *dev = video_drvdata(file);
 263         struct cedrus_ctx *ctx = container_of(file->private_data,
 264                                               struct cedrus_ctx, fh);
 265 
 266         mutex_lock(&dev->dev_mutex);
 267 
 268         v4l2_fh_del(&ctx->fh);
 269         v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 270 
 271         v4l2_ctrl_handler_free(&ctx->hdl);
 272         kfree(ctx->ctrls);
 273 
 274         v4l2_fh_exit(&ctx->fh);
 275 
 276         kfree(ctx);
 277 
 278         mutex_unlock(&dev->dev_mutex);
 279 
 280         return 0;
 281 }
 282 
 283 static const struct v4l2_file_operations cedrus_fops = {
 284         .owner          = THIS_MODULE,
 285         .open           = cedrus_open,
 286         .release        = cedrus_release,
 287         .poll           = v4l2_m2m_fop_poll,
 288         .unlocked_ioctl = video_ioctl2,
 289         .mmap           = v4l2_m2m_fop_mmap,
 290 };
 291 
 292 static const struct video_device cedrus_video_device = {
 293         .name           = CEDRUS_NAME,
 294         .vfl_dir        = VFL_DIR_M2M,
 295         .fops           = &cedrus_fops,
 296         .ioctl_ops      = &cedrus_ioctl_ops,
 297         .minor          = -1,
 298         .release        = video_device_release_empty,
 299         .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
 300 };
 301 
 302 static const struct v4l2_m2m_ops cedrus_m2m_ops = {
 303         .device_run     = cedrus_device_run,
 304 };
 305 
 306 static const struct media_device_ops cedrus_m2m_media_ops = {
 307         .req_validate   = cedrus_request_validate,
 308         .req_queue      = v4l2_m2m_request_queue,
 309 };
 310 
 311 static int cedrus_probe(struct platform_device *pdev)
 312 {
 313         struct cedrus_dev *dev;
 314         struct video_device *vfd;
 315         int ret;
 316 
 317         dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 318         if (!dev)
 319                 return -ENOMEM;
 320 
 321         dev->vfd = cedrus_video_device;
 322         dev->dev = &pdev->dev;
 323         dev->pdev = pdev;
 324 
 325         ret = cedrus_hw_probe(dev);
 326         if (ret) {
 327                 dev_err(&pdev->dev, "Failed to probe hardware\n");
 328                 return ret;
 329         }
 330 
 331         dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
 332         dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
 333 
 334         mutex_init(&dev->dev_mutex);
 335 
 336         ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
 337         if (ret) {
 338                 dev_err(&pdev->dev, "Failed to register V4L2 device\n");
 339                 return ret;
 340         }
 341 
 342         vfd = &dev->vfd;
 343         vfd->lock = &dev->dev_mutex;
 344         vfd->v4l2_dev = &dev->v4l2_dev;
 345 
 346         snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
 347         video_set_drvdata(vfd, dev);
 348 
 349         dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
 350         if (IS_ERR(dev->m2m_dev)) {
 351                 v4l2_err(&dev->v4l2_dev,
 352                          "Failed to initialize V4L2 M2M device\n");
 353                 ret = PTR_ERR(dev->m2m_dev);
 354 
 355                 goto err_v4l2;
 356         }
 357 
 358         dev->mdev.dev = &pdev->dev;
 359         strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
 360         strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME,
 361                 sizeof(dev->mdev.bus_info));
 362 
 363         media_device_init(&dev->mdev);
 364         dev->mdev.ops = &cedrus_m2m_media_ops;
 365         dev->v4l2_dev.mdev = &dev->mdev;
 366 
 367         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 368         if (ret) {
 369                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
 370                 goto err_m2m;
 371         }
 372 
 373         v4l2_info(&dev->v4l2_dev,
 374                   "Device registered as /dev/video%d\n", vfd->num);
 375 
 376         ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
 377                                                  MEDIA_ENT_F_PROC_VIDEO_DECODER);
 378         if (ret) {
 379                 v4l2_err(&dev->v4l2_dev,
 380                          "Failed to initialize V4L2 M2M media controller\n");
 381                 goto err_video;
 382         }
 383 
 384         ret = media_device_register(&dev->mdev);
 385         if (ret) {
 386                 v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
 387                 goto err_m2m_mc;
 388         }
 389 
 390         platform_set_drvdata(pdev, dev);
 391 
 392         return 0;
 393 
 394 err_m2m_mc:
 395         v4l2_m2m_unregister_media_controller(dev->m2m_dev);
 396 err_video:
 397         video_unregister_device(&dev->vfd);
 398 err_m2m:
 399         v4l2_m2m_release(dev->m2m_dev);
 400 err_v4l2:
 401         v4l2_device_unregister(&dev->v4l2_dev);
 402 
 403         return ret;
 404 }
 405 
 406 static int cedrus_remove(struct platform_device *pdev)
 407 {
 408         struct cedrus_dev *dev = platform_get_drvdata(pdev);
 409 
 410         if (media_devnode_is_registered(dev->mdev.devnode)) {
 411                 media_device_unregister(&dev->mdev);
 412                 v4l2_m2m_unregister_media_controller(dev->m2m_dev);
 413                 media_device_cleanup(&dev->mdev);
 414         }
 415 
 416         v4l2_m2m_release(dev->m2m_dev);
 417         video_unregister_device(&dev->vfd);
 418         v4l2_device_unregister(&dev->v4l2_dev);
 419 
 420         cedrus_hw_remove(dev);
 421 
 422         return 0;
 423 }
 424 
 425 static const struct cedrus_variant sun4i_a10_cedrus_variant = {
 426         .mod_rate       = 320000000,
 427 };
 428 
 429 static const struct cedrus_variant sun5i_a13_cedrus_variant = {
 430         .mod_rate       = 320000000,
 431 };
 432 
 433 static const struct cedrus_variant sun7i_a20_cedrus_variant = {
 434         .mod_rate       = 320000000,
 435 };
 436 
 437 static const struct cedrus_variant sun8i_a33_cedrus_variant = {
 438         .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 439         .mod_rate       = 320000000,
 440 };
 441 
 442 static const struct cedrus_variant sun8i_h3_cedrus_variant = {
 443         .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 444         .mod_rate       = 402000000,
 445 };
 446 
 447 static const struct cedrus_variant sun50i_a64_cedrus_variant = {
 448         .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 449         .mod_rate       = 402000000,
 450 };
 451 
 452 static const struct cedrus_variant sun50i_h5_cedrus_variant = {
 453         .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 454         .mod_rate       = 402000000,
 455 };
 456 
 457 static const struct cedrus_variant sun50i_h6_cedrus_variant = {
 458         .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 459         .quirks         = CEDRUS_QUIRK_NO_DMA_OFFSET,
 460         .mod_rate       = 600000000,
 461 };
 462 
 463 static const struct of_device_id cedrus_dt_match[] = {
 464         {
 465                 .compatible = "allwinner,sun4i-a10-video-engine",
 466                 .data = &sun4i_a10_cedrus_variant,
 467         },
 468         {
 469                 .compatible = "allwinner,sun5i-a13-video-engine",
 470                 .data = &sun5i_a13_cedrus_variant,
 471         },
 472         {
 473                 .compatible = "allwinner,sun7i-a20-video-engine",
 474                 .data = &sun7i_a20_cedrus_variant,
 475         },
 476         {
 477                 .compatible = "allwinner,sun8i-a33-video-engine",
 478                 .data = &sun8i_a33_cedrus_variant,
 479         },
 480         {
 481                 .compatible = "allwinner,sun8i-h3-video-engine",
 482                 .data = &sun8i_h3_cedrus_variant,
 483         },
 484         {
 485                 .compatible = "allwinner,sun50i-a64-video-engine",
 486                 .data = &sun50i_a64_cedrus_variant,
 487         },
 488         {
 489                 .compatible = "allwinner,sun50i-h5-video-engine",
 490                 .data = &sun50i_h5_cedrus_variant,
 491         },
 492         {
 493                 .compatible = "allwinner,sun50i-h6-video-engine",
 494                 .data = &sun50i_h6_cedrus_variant,
 495         },
 496         { /* sentinel */ }
 497 };
 498 MODULE_DEVICE_TABLE(of, cedrus_dt_match);
 499 
 500 static struct platform_driver cedrus_driver = {
 501         .probe          = cedrus_probe,
 502         .remove         = cedrus_remove,
 503         .driver         = {
 504                 .name           = CEDRUS_NAME,
 505                 .of_match_table = of_match_ptr(cedrus_dt_match),
 506         },
 507 };
 508 module_platform_driver(cedrus_driver);
 509 
 510 MODULE_LICENSE("GPL v2");
 511 MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
 512 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
 513 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
 514 MODULE_DESCRIPTION("Cedrus VPU driver");

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