root/drivers/media/platform/qcom/venus/core.c

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

DEFINITIONS

This source file includes following definitions.
  1. venus_event_notify
  2. venus_sys_error_handler
  3. venus_clks_get
  4. venus_clks_enable
  5. venus_clks_disable
  6. to_v4l2_codec_type
  7. venus_enumerate_codecs
  8. venus_probe
  9. venus_remove
  10. venus_runtime_suspend
  11. venus_runtime_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
   4  * Copyright (C) 2017 Linaro Ltd.
   5  */
   6 #include <linux/clk.h>
   7 #include <linux/init.h>
   8 #include <linux/ioctl.h>
   9 #include <linux/list.h>
  10 #include <linux/module.h>
  11 #include <linux/of_device.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/slab.h>
  14 #include <linux/types.h>
  15 #include <linux/pm_runtime.h>
  16 #include <media/videobuf2-v4l2.h>
  17 #include <media/v4l2-mem2mem.h>
  18 #include <media/v4l2-ioctl.h>
  19 
  20 #include "core.h"
  21 #include "vdec.h"
  22 #include "venc.h"
  23 #include "firmware.h"
  24 
  25 static void venus_event_notify(struct venus_core *core, u32 event)
  26 {
  27         struct venus_inst *inst;
  28 
  29         switch (event) {
  30         case EVT_SYS_WATCHDOG_TIMEOUT:
  31         case EVT_SYS_ERROR:
  32                 break;
  33         default:
  34                 return;
  35         }
  36 
  37         mutex_lock(&core->lock);
  38         core->sys_error = true;
  39         list_for_each_entry(inst, &core->instances, list)
  40                 inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL);
  41         mutex_unlock(&core->lock);
  42 
  43         disable_irq_nosync(core->irq);
  44 
  45         /*
  46          * Delay recovery to ensure venus has completed any pending cache
  47          * operations. Without this sleep, we see device reset when firmware is
  48          * unloaded after a system error.
  49          */
  50         schedule_delayed_work(&core->work, msecs_to_jiffies(100));
  51 }
  52 
  53 static const struct hfi_core_ops venus_core_ops = {
  54         .event_notify = venus_event_notify,
  55 };
  56 
  57 static void venus_sys_error_handler(struct work_struct *work)
  58 {
  59         struct venus_core *core =
  60                         container_of(work, struct venus_core, work.work);
  61         int ret = 0;
  62 
  63         dev_warn(core->dev, "system error has occurred, starting recovery!\n");
  64 
  65         pm_runtime_get_sync(core->dev);
  66 
  67         hfi_core_deinit(core, true);
  68         hfi_destroy(core);
  69         mutex_lock(&core->lock);
  70         venus_shutdown(core);
  71 
  72         pm_runtime_put_sync(core->dev);
  73 
  74         ret |= hfi_create(core, &venus_core_ops);
  75 
  76         pm_runtime_get_sync(core->dev);
  77 
  78         ret |= venus_boot(core);
  79 
  80         ret |= hfi_core_resume(core, true);
  81 
  82         enable_irq(core->irq);
  83 
  84         mutex_unlock(&core->lock);
  85 
  86         ret |= hfi_core_init(core);
  87 
  88         pm_runtime_put_sync(core->dev);
  89 
  90         if (ret) {
  91                 disable_irq_nosync(core->irq);
  92                 dev_warn(core->dev, "recovery failed (%d)\n", ret);
  93                 schedule_delayed_work(&core->work, msecs_to_jiffies(10));
  94                 return;
  95         }
  96 
  97         mutex_lock(&core->lock);
  98         core->sys_error = false;
  99         mutex_unlock(&core->lock);
 100 }
 101 
 102 static int venus_clks_get(struct venus_core *core)
 103 {
 104         const struct venus_resources *res = core->res;
 105         struct device *dev = core->dev;
 106         unsigned int i;
 107 
 108         for (i = 0; i < res->clks_num; i++) {
 109                 core->clks[i] = devm_clk_get(dev, res->clks[i]);
 110                 if (IS_ERR(core->clks[i]))
 111                         return PTR_ERR(core->clks[i]);
 112         }
 113 
 114         return 0;
 115 }
 116 
 117 static int venus_clks_enable(struct venus_core *core)
 118 {
 119         const struct venus_resources *res = core->res;
 120         unsigned int i;
 121         int ret;
 122 
 123         for (i = 0; i < res->clks_num; i++) {
 124                 ret = clk_prepare_enable(core->clks[i]);
 125                 if (ret)
 126                         goto err;
 127         }
 128 
 129         return 0;
 130 err:
 131         while (i--)
 132                 clk_disable_unprepare(core->clks[i]);
 133 
 134         return ret;
 135 }
 136 
 137 static void venus_clks_disable(struct venus_core *core)
 138 {
 139         const struct venus_resources *res = core->res;
 140         unsigned int i = res->clks_num;
 141 
 142         while (i--)
 143                 clk_disable_unprepare(core->clks[i]);
 144 }
 145 
 146 static u32 to_v4l2_codec_type(u32 codec)
 147 {
 148         switch (codec) {
 149         case HFI_VIDEO_CODEC_H264:
 150                 return V4L2_PIX_FMT_H264;
 151         case HFI_VIDEO_CODEC_H263:
 152                 return V4L2_PIX_FMT_H263;
 153         case HFI_VIDEO_CODEC_MPEG1:
 154                 return V4L2_PIX_FMT_MPEG1;
 155         case HFI_VIDEO_CODEC_MPEG2:
 156                 return V4L2_PIX_FMT_MPEG2;
 157         case HFI_VIDEO_CODEC_MPEG4:
 158                 return V4L2_PIX_FMT_MPEG4;
 159         case HFI_VIDEO_CODEC_VC1:
 160                 return V4L2_PIX_FMT_VC1_ANNEX_G;
 161         case HFI_VIDEO_CODEC_VP8:
 162                 return V4L2_PIX_FMT_VP8;
 163         case HFI_VIDEO_CODEC_VP9:
 164                 return V4L2_PIX_FMT_VP9;
 165         case HFI_VIDEO_CODEC_DIVX:
 166         case HFI_VIDEO_CODEC_DIVX_311:
 167                 return V4L2_PIX_FMT_XVID;
 168         default:
 169                 return 0;
 170         }
 171 }
 172 
 173 static int venus_enumerate_codecs(struct venus_core *core, u32 type)
 174 {
 175         const struct hfi_inst_ops dummy_ops = {};
 176         struct venus_inst *inst;
 177         u32 codec, codecs;
 178         unsigned int i;
 179         int ret;
 180 
 181         if (core->res->hfi_version != HFI_VERSION_1XX)
 182                 return 0;
 183 
 184         inst = kzalloc(sizeof(*inst), GFP_KERNEL);
 185         if (!inst)
 186                 return -ENOMEM;
 187 
 188         mutex_init(&inst->lock);
 189         inst->core = core;
 190         inst->session_type = type;
 191         if (type == VIDC_SESSION_TYPE_DEC)
 192                 codecs = core->dec_codecs;
 193         else
 194                 codecs = core->enc_codecs;
 195 
 196         ret = hfi_session_create(inst, &dummy_ops);
 197         if (ret)
 198                 goto err;
 199 
 200         for (i = 0; i < MAX_CODEC_NUM; i++) {
 201                 codec = (1UL << i) & codecs;
 202                 if (!codec)
 203                         continue;
 204 
 205                 ret = hfi_session_init(inst, to_v4l2_codec_type(codec));
 206                 if (ret)
 207                         goto done;
 208 
 209                 ret = hfi_session_deinit(inst);
 210                 if (ret)
 211                         goto done;
 212         }
 213 
 214 done:
 215         hfi_session_destroy(inst);
 216 err:
 217         mutex_destroy(&inst->lock);
 218         kfree(inst);
 219 
 220         return ret;
 221 }
 222 
 223 static int venus_probe(struct platform_device *pdev)
 224 {
 225         struct device *dev = &pdev->dev;
 226         struct venus_core *core;
 227         struct resource *r;
 228         int ret;
 229 
 230         core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
 231         if (!core)
 232                 return -ENOMEM;
 233 
 234         core->dev = dev;
 235         platform_set_drvdata(pdev, core);
 236 
 237         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 238         core->base = devm_ioremap_resource(dev, r);
 239         if (IS_ERR(core->base))
 240                 return PTR_ERR(core->base);
 241 
 242         core->irq = platform_get_irq(pdev, 0);
 243         if (core->irq < 0)
 244                 return core->irq;
 245 
 246         core->res = of_device_get_match_data(dev);
 247         if (!core->res)
 248                 return -ENODEV;
 249 
 250         ret = venus_clks_get(core);
 251         if (ret)
 252                 return ret;
 253 
 254         ret = dma_set_mask_and_coherent(dev, core->res->dma_mask);
 255         if (ret)
 256                 return ret;
 257 
 258         if (!dev->dma_parms) {
 259                 dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
 260                                               GFP_KERNEL);
 261                 if (!dev->dma_parms)
 262                         return -ENOMEM;
 263         }
 264         dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
 265 
 266         INIT_LIST_HEAD(&core->instances);
 267         mutex_init(&core->lock);
 268         INIT_DELAYED_WORK(&core->work, venus_sys_error_handler);
 269 
 270         ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread,
 271                                         IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 272                                         "venus", core);
 273         if (ret)
 274                 return ret;
 275 
 276         ret = hfi_create(core, &venus_core_ops);
 277         if (ret)
 278                 return ret;
 279 
 280         pm_runtime_enable(dev);
 281 
 282         ret = pm_runtime_get_sync(dev);
 283         if (ret < 0)
 284                 goto err_runtime_disable;
 285 
 286         ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 287         if (ret)
 288                 goto err_runtime_disable;
 289 
 290         ret = venus_firmware_init(core);
 291         if (ret)
 292                 goto err_runtime_disable;
 293 
 294         ret = venus_boot(core);
 295         if (ret)
 296                 goto err_runtime_disable;
 297 
 298         ret = hfi_core_resume(core, true);
 299         if (ret)
 300                 goto err_venus_shutdown;
 301 
 302         ret = hfi_core_init(core);
 303         if (ret)
 304                 goto err_venus_shutdown;
 305 
 306         ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC);
 307         if (ret)
 308                 goto err_venus_shutdown;
 309 
 310         ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC);
 311         if (ret)
 312                 goto err_venus_shutdown;
 313 
 314         ret = v4l2_device_register(dev, &core->v4l2_dev);
 315         if (ret)
 316                 goto err_core_deinit;
 317 
 318         ret = pm_runtime_put_sync(dev);
 319         if (ret)
 320                 goto err_dev_unregister;
 321 
 322         return 0;
 323 
 324 err_dev_unregister:
 325         v4l2_device_unregister(&core->v4l2_dev);
 326 err_core_deinit:
 327         hfi_core_deinit(core, false);
 328 err_venus_shutdown:
 329         venus_shutdown(core);
 330 err_runtime_disable:
 331         pm_runtime_set_suspended(dev);
 332         pm_runtime_disable(dev);
 333         hfi_destroy(core);
 334         return ret;
 335 }
 336 
 337 static int venus_remove(struct platform_device *pdev)
 338 {
 339         struct venus_core *core = platform_get_drvdata(pdev);
 340         struct device *dev = core->dev;
 341         int ret;
 342 
 343         ret = pm_runtime_get_sync(dev);
 344         WARN_ON(ret < 0);
 345 
 346         ret = hfi_core_deinit(core, true);
 347         WARN_ON(ret);
 348 
 349         hfi_destroy(core);
 350         venus_shutdown(core);
 351         of_platform_depopulate(dev);
 352 
 353         venus_firmware_deinit(core);
 354 
 355         pm_runtime_put_sync(dev);
 356         pm_runtime_disable(dev);
 357 
 358         v4l2_device_unregister(&core->v4l2_dev);
 359 
 360         return ret;
 361 }
 362 
 363 static __maybe_unused int venus_runtime_suspend(struct device *dev)
 364 {
 365         struct venus_core *core = dev_get_drvdata(dev);
 366         int ret;
 367 
 368         ret = hfi_core_suspend(core);
 369 
 370         venus_clks_disable(core);
 371 
 372         return ret;
 373 }
 374 
 375 static __maybe_unused int venus_runtime_resume(struct device *dev)
 376 {
 377         struct venus_core *core = dev_get_drvdata(dev);
 378         int ret;
 379 
 380         ret = venus_clks_enable(core);
 381         if (ret)
 382                 return ret;
 383 
 384         ret = hfi_core_resume(core, false);
 385         if (ret)
 386                 goto err_clks_disable;
 387 
 388         return 0;
 389 
 390 err_clks_disable:
 391         venus_clks_disable(core);
 392         return ret;
 393 }
 394 
 395 static const struct dev_pm_ops venus_pm_ops = {
 396         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 397                                 pm_runtime_force_resume)
 398         SET_RUNTIME_PM_OPS(venus_runtime_suspend, venus_runtime_resume, NULL)
 399 };
 400 
 401 static const struct freq_tbl msm8916_freq_table[] = {
 402         { 352800, 228570000 },  /* 1920x1088 @ 30 + 1280x720 @ 30 */
 403         { 244800, 160000000 },  /* 1920x1088 @ 30 */
 404         { 108000, 100000000 },  /* 1280x720 @ 30 */
 405 };
 406 
 407 static const struct reg_val msm8916_reg_preset[] = {
 408         { 0xe0020, 0x05555556 },
 409         { 0xe0024, 0x05555556 },
 410         { 0x80124, 0x00000003 },
 411 };
 412 
 413 static const struct venus_resources msm8916_res = {
 414         .freq_tbl = msm8916_freq_table,
 415         .freq_tbl_size = ARRAY_SIZE(msm8916_freq_table),
 416         .reg_tbl = msm8916_reg_preset,
 417         .reg_tbl_size = ARRAY_SIZE(msm8916_reg_preset),
 418         .clks = { "core", "iface", "bus", },
 419         .clks_num = 3,
 420         .max_load = 352800, /* 720p@30 + 1080p@30 */
 421         .hfi_version = HFI_VERSION_1XX,
 422         .vmem_id = VIDC_RESOURCE_NONE,
 423         .vmem_size = 0,
 424         .vmem_addr = 0,
 425         .dma_mask = 0xddc00000 - 1,
 426         .fwname = "qcom/venus-1.8/venus.mdt",
 427 };
 428 
 429 static const struct freq_tbl msm8996_freq_table[] = {
 430         { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */
 431         {  972000, 520000000 }, /* 4k UHD @ 30 */
 432         {  489600, 346666667 }, /* 1080p @ 60 */
 433         {  244800, 150000000 }, /* 1080p @ 30 */
 434         {  108000,  75000000 }, /* 720p @ 30 */
 435 };
 436 
 437 static const struct reg_val msm8996_reg_preset[] = {
 438         { 0x80010, 0xffffffff },
 439         { 0x80018, 0x00001556 },
 440         { 0x8001C, 0x00001556 },
 441 };
 442 
 443 static const struct venus_resources msm8996_res = {
 444         .freq_tbl = msm8996_freq_table,
 445         .freq_tbl_size = ARRAY_SIZE(msm8996_freq_table),
 446         .reg_tbl = msm8996_reg_preset,
 447         .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset),
 448         .clks = {"core", "iface", "bus", "mbus" },
 449         .clks_num = 4,
 450         .max_load = 2563200,
 451         .hfi_version = HFI_VERSION_3XX,
 452         .vmem_id = VIDC_RESOURCE_NONE,
 453         .vmem_size = 0,
 454         .vmem_addr = 0,
 455         .dma_mask = 0xddc00000 - 1,
 456         .fwname = "qcom/venus-4.2/venus.mdt",
 457 };
 458 
 459 static const struct freq_tbl sdm845_freq_table[] = {
 460         { 3110400, 533000000 }, /* 4096x2160@90 */
 461         { 2073600, 444000000 }, /* 4096x2160@60 */
 462         { 1944000, 404000000 }, /* 3840x2160@60 */
 463         {  972000, 330000000 }, /* 3840x2160@30 */
 464         {  489600, 200000000 }, /* 1920x1080@60 */
 465         {  244800, 100000000 }, /* 1920x1080@30 */
 466 };
 467 
 468 static const struct venus_resources sdm845_res = {
 469         .freq_tbl = sdm845_freq_table,
 470         .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table),
 471         .clks = {"core", "iface", "bus" },
 472         .clks_num = 3,
 473         .max_load = 3110400,    /* 4096x2160@90 */
 474         .hfi_version = HFI_VERSION_4XX,
 475         .vmem_id = VIDC_RESOURCE_NONE,
 476         .vmem_size = 0,
 477         .vmem_addr = 0,
 478         .dma_mask = 0xe0000000 - 1,
 479         .fwname = "qcom/venus-5.2/venus.mdt",
 480 };
 481 
 482 static const struct of_device_id venus_dt_match[] = {
 483         { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, },
 484         { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, },
 485         { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, },
 486         { }
 487 };
 488 MODULE_DEVICE_TABLE(of, venus_dt_match);
 489 
 490 static struct platform_driver qcom_venus_driver = {
 491         .probe = venus_probe,
 492         .remove = venus_remove,
 493         .driver = {
 494                 .name = "qcom-venus",
 495                 .of_match_table = venus_dt_match,
 496                 .pm = &venus_pm_ops,
 497         },
 498 };
 499 module_platform_driver(qcom_venus_driver);
 500 
 501 MODULE_ALIAS("platform:qcom-venus");
 502 MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver");
 503 MODULE_LICENSE("GPL v2");

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