linux/drivers/media/platform/qcom/venus/hfi.c
<<
>>
Prefs
   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/slab.h>
   7#include <linux/mutex.h>
   8#include <linux/list.h>
   9#include <linux/completion.h>
  10#include <linux/platform_device.h>
  11#include <linux/videodev2.h>
  12
  13#include "core.h"
  14#include "hfi.h"
  15#include "hfi_cmds.h"
  16#include "hfi_venus.h"
  17
  18#define TIMEOUT         msecs_to_jiffies(1000)
  19
  20static u32 to_codec_type(u32 pixfmt)
  21{
  22        switch (pixfmt) {
  23        case V4L2_PIX_FMT_H264:
  24        case V4L2_PIX_FMT_H264_NO_SC:
  25                return HFI_VIDEO_CODEC_H264;
  26        case V4L2_PIX_FMT_H263:
  27                return HFI_VIDEO_CODEC_H263;
  28        case V4L2_PIX_FMT_MPEG1:
  29                return HFI_VIDEO_CODEC_MPEG1;
  30        case V4L2_PIX_FMT_MPEG2:
  31                return HFI_VIDEO_CODEC_MPEG2;
  32        case V4L2_PIX_FMT_MPEG4:
  33                return HFI_VIDEO_CODEC_MPEG4;
  34        case V4L2_PIX_FMT_VC1_ANNEX_G:
  35        case V4L2_PIX_FMT_VC1_ANNEX_L:
  36                return HFI_VIDEO_CODEC_VC1;
  37        case V4L2_PIX_FMT_VP8:
  38                return HFI_VIDEO_CODEC_VP8;
  39        case V4L2_PIX_FMT_VP9:
  40                return HFI_VIDEO_CODEC_VP9;
  41        case V4L2_PIX_FMT_XVID:
  42                return HFI_VIDEO_CODEC_DIVX;
  43        case V4L2_PIX_FMT_HEVC:
  44                return HFI_VIDEO_CODEC_HEVC;
  45        default:
  46                return 0;
  47        }
  48}
  49
  50int hfi_core_init(struct venus_core *core)
  51{
  52        int ret = 0;
  53
  54        mutex_lock(&core->lock);
  55
  56        if (core->state >= CORE_INIT)
  57                goto unlock;
  58
  59        reinit_completion(&core->done);
  60
  61        ret = core->ops->core_init(core);
  62        if (ret)
  63                goto unlock;
  64
  65        ret = wait_for_completion_timeout(&core->done, TIMEOUT);
  66        if (!ret) {
  67                ret = -ETIMEDOUT;
  68                goto unlock;
  69        }
  70
  71        ret = 0;
  72
  73        if (core->error != HFI_ERR_NONE) {
  74                ret = -EIO;
  75                goto unlock;
  76        }
  77
  78        core->state = CORE_INIT;
  79unlock:
  80        mutex_unlock(&core->lock);
  81        return ret;
  82}
  83
  84int hfi_core_deinit(struct venus_core *core, bool blocking)
  85{
  86        int ret = 0, empty;
  87
  88        mutex_lock(&core->lock);
  89
  90        if (core->state == CORE_UNINIT)
  91                goto unlock;
  92
  93        empty = list_empty(&core->instances);
  94
  95        if (!empty && !blocking) {
  96                ret = -EBUSY;
  97                goto unlock;
  98        }
  99
 100        if (!empty) {
 101                mutex_unlock(&core->lock);
 102                wait_var_event(&core->insts_count,
 103                               !atomic_read(&core->insts_count));
 104                mutex_lock(&core->lock);
 105        }
 106
 107        ret = core->ops->core_deinit(core);
 108
 109        if (!ret)
 110                core->state = CORE_UNINIT;
 111
 112unlock:
 113        mutex_unlock(&core->lock);
 114        return ret;
 115}
 116
 117int hfi_core_suspend(struct venus_core *core)
 118{
 119        if (core->state != CORE_INIT)
 120                return 0;
 121
 122        return core->ops->suspend(core);
 123}
 124
 125int hfi_core_resume(struct venus_core *core, bool force)
 126{
 127        if (!force && core->state != CORE_INIT)
 128                return 0;
 129
 130        return core->ops->resume(core);
 131}
 132
 133int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
 134{
 135        return core->ops->core_trigger_ssr(core, type);
 136}
 137
 138int hfi_core_ping(struct venus_core *core)
 139{
 140        int ret;
 141
 142        mutex_lock(&core->lock);
 143
 144        ret = core->ops->core_ping(core, 0xbeef);
 145        if (ret)
 146                goto unlock;
 147
 148        ret = wait_for_completion_timeout(&core->done, TIMEOUT);
 149        if (!ret) {
 150                ret = -ETIMEDOUT;
 151                goto unlock;
 152        }
 153        ret = 0;
 154        if (core->error != HFI_ERR_NONE)
 155                ret = -ENODEV;
 156unlock:
 157        mutex_unlock(&core->lock);
 158        return ret;
 159}
 160
 161static int wait_session_msg(struct venus_inst *inst)
 162{
 163        int ret;
 164
 165        ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
 166        if (!ret)
 167                return -ETIMEDOUT;
 168
 169        if (inst->error != HFI_ERR_NONE)
 170                return -EIO;
 171
 172        return 0;
 173}
 174
 175int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
 176{
 177        struct venus_core *core = inst->core;
 178        bool max;
 179        int ret;
 180
 181        if (!ops)
 182                return -EINVAL;
 183
 184        inst->state = INST_UNINIT;
 185        init_completion(&inst->done);
 186        inst->ops = ops;
 187
 188        mutex_lock(&core->lock);
 189
 190        max = atomic_add_unless(&core->insts_count, 1,
 191                                core->max_sessions_supported);
 192        if (!max) {
 193                ret = -EAGAIN;
 194        } else {
 195                list_add_tail(&inst->list, &core->instances);
 196                ret = 0;
 197        }
 198
 199        mutex_unlock(&core->lock);
 200
 201        return ret;
 202}
 203EXPORT_SYMBOL_GPL(hfi_session_create);
 204
 205int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
 206{
 207        struct venus_core *core = inst->core;
 208        const struct hfi_ops *ops = core->ops;
 209        int ret;
 210
 211        /*
 212         * If core shutdown is in progress or if we are in system
 213         * recovery, return an error as during system error recovery
 214         * session_init() can't pass successfully
 215         */
 216        mutex_lock(&core->lock);
 217        if (!core->ops || core->sys_error) {
 218                mutex_unlock(&core->lock);
 219                return -EIO;
 220        }
 221        mutex_unlock(&core->lock);
 222
 223        if (inst->state != INST_UNINIT)
 224                return -EALREADY;
 225
 226        inst->hfi_codec = to_codec_type(pixfmt);
 227        reinit_completion(&inst->done);
 228
 229        ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
 230        if (ret)
 231                return ret;
 232
 233        ret = wait_session_msg(inst);
 234        if (ret)
 235                return ret;
 236
 237        inst->state = INST_INIT;
 238
 239        return 0;
 240}
 241EXPORT_SYMBOL_GPL(hfi_session_init);
 242
 243void hfi_session_destroy(struct venus_inst *inst)
 244{
 245        struct venus_core *core = inst->core;
 246
 247        mutex_lock(&core->lock);
 248        list_del_init(&inst->list);
 249        if (atomic_dec_and_test(&core->insts_count))
 250                wake_up_var(&core->insts_count);
 251        mutex_unlock(&core->lock);
 252}
 253EXPORT_SYMBOL_GPL(hfi_session_destroy);
 254
 255int hfi_session_deinit(struct venus_inst *inst)
 256{
 257        const struct hfi_ops *ops = inst->core->ops;
 258        int ret;
 259
 260        if (inst->state == INST_UNINIT)
 261                return 0;
 262
 263        if (inst->state < INST_INIT)
 264                return -EINVAL;
 265
 266        reinit_completion(&inst->done);
 267
 268        ret = ops->session_end(inst);
 269        if (ret)
 270                return ret;
 271
 272        ret = wait_session_msg(inst);
 273        if (ret)
 274                return ret;
 275
 276        inst->state = INST_UNINIT;
 277
 278        return 0;
 279}
 280EXPORT_SYMBOL_GPL(hfi_session_deinit);
 281
 282int hfi_session_start(struct venus_inst *inst)
 283{
 284        const struct hfi_ops *ops = inst->core->ops;
 285        int ret;
 286
 287        if (inst->state != INST_LOAD_RESOURCES)
 288                return -EINVAL;
 289
 290        reinit_completion(&inst->done);
 291
 292        ret = ops->session_start(inst);
 293        if (ret)
 294                return ret;
 295
 296        ret = wait_session_msg(inst);
 297        if (ret)
 298                return ret;
 299
 300        inst->state = INST_START;
 301
 302        return 0;
 303}
 304EXPORT_SYMBOL_GPL(hfi_session_start);
 305
 306int hfi_session_stop(struct venus_inst *inst)
 307{
 308        const struct hfi_ops *ops = inst->core->ops;
 309        int ret;
 310
 311        if (inst->state != INST_START)
 312                return -EINVAL;
 313
 314        reinit_completion(&inst->done);
 315
 316        ret = ops->session_stop(inst);
 317        if (ret)
 318                return ret;
 319
 320        ret = wait_session_msg(inst);
 321        if (ret)
 322                return ret;
 323
 324        inst->state = INST_STOP;
 325
 326        return 0;
 327}
 328EXPORT_SYMBOL_GPL(hfi_session_stop);
 329
 330int hfi_session_continue(struct venus_inst *inst)
 331{
 332        struct venus_core *core = inst->core;
 333
 334        if (core->res->hfi_version == HFI_VERSION_1XX)
 335                return 0;
 336
 337        return core->ops->session_continue(inst);
 338}
 339EXPORT_SYMBOL_GPL(hfi_session_continue);
 340
 341int hfi_session_abort(struct venus_inst *inst)
 342{
 343        const struct hfi_ops *ops = inst->core->ops;
 344        int ret;
 345
 346        reinit_completion(&inst->done);
 347
 348        ret = ops->session_abort(inst);
 349        if (ret)
 350                return ret;
 351
 352        ret = wait_session_msg(inst);
 353        if (ret)
 354                return ret;
 355
 356        return 0;
 357}
 358EXPORT_SYMBOL_GPL(hfi_session_abort);
 359
 360int hfi_session_load_res(struct venus_inst *inst)
 361{
 362        const struct hfi_ops *ops = inst->core->ops;
 363        int ret;
 364
 365        if (inst->state != INST_INIT)
 366                return -EINVAL;
 367
 368        reinit_completion(&inst->done);
 369
 370        ret = ops->session_load_res(inst);
 371        if (ret)
 372                return ret;
 373
 374        ret = wait_session_msg(inst);
 375        if (ret)
 376                return ret;
 377
 378        inst->state = INST_LOAD_RESOURCES;
 379
 380        return 0;
 381}
 382
 383int hfi_session_unload_res(struct venus_inst *inst)
 384{
 385        const struct hfi_ops *ops = inst->core->ops;
 386        int ret;
 387
 388        if (inst->state != INST_STOP)
 389                return -EINVAL;
 390
 391        reinit_completion(&inst->done);
 392
 393        ret = ops->session_release_res(inst);
 394        if (ret)
 395                return ret;
 396
 397        ret = wait_session_msg(inst);
 398        if (ret)
 399                return ret;
 400
 401        inst->state = INST_RELEASE_RESOURCES;
 402
 403        return 0;
 404}
 405EXPORT_SYMBOL_GPL(hfi_session_unload_res);
 406
 407int hfi_session_flush(struct venus_inst *inst, u32 type, bool block)
 408{
 409        const struct hfi_ops *ops = inst->core->ops;
 410        int ret;
 411
 412        reinit_completion(&inst->done);
 413
 414        ret = ops->session_flush(inst, type);
 415        if (ret)
 416                return ret;
 417
 418        if (block) {
 419                ret = wait_session_msg(inst);
 420                if (ret)
 421                        return ret;
 422        }
 423
 424        return 0;
 425}
 426EXPORT_SYMBOL_GPL(hfi_session_flush);
 427
 428int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
 429{
 430        const struct hfi_ops *ops = inst->core->ops;
 431
 432        return ops->session_set_buffers(inst, bd);
 433}
 434
 435int hfi_session_unset_buffers(struct venus_inst *inst,
 436                              struct hfi_buffer_desc *bd)
 437{
 438        const struct hfi_ops *ops = inst->core->ops;
 439        int ret;
 440
 441        reinit_completion(&inst->done);
 442
 443        ret = ops->session_unset_buffers(inst, bd);
 444        if (ret)
 445                return ret;
 446
 447        if (!bd->response_required)
 448                return 0;
 449
 450        ret = wait_session_msg(inst);
 451        if (ret)
 452                return ret;
 453
 454        return 0;
 455}
 456
 457int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
 458                             union hfi_get_property *hprop)
 459{
 460        const struct hfi_ops *ops = inst->core->ops;
 461        int ret;
 462
 463        if (inst->state < INST_INIT || inst->state >= INST_STOP)
 464                return -EINVAL;
 465
 466        reinit_completion(&inst->done);
 467
 468        ret = ops->session_get_property(inst, ptype);
 469        if (ret)
 470                return ret;
 471
 472        ret = wait_session_msg(inst);
 473        if (ret)
 474                return ret;
 475
 476        *hprop = inst->hprop;
 477
 478        return 0;
 479}
 480EXPORT_SYMBOL_GPL(hfi_session_get_property);
 481
 482int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
 483{
 484        const struct hfi_ops *ops = inst->core->ops;
 485
 486        if (inst->state < INST_INIT || inst->state >= INST_STOP)
 487                return -EINVAL;
 488
 489        return ops->session_set_property(inst, ptype, pdata);
 490}
 491EXPORT_SYMBOL_GPL(hfi_session_set_property);
 492
 493int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
 494{
 495        const struct hfi_ops *ops = inst->core->ops;
 496
 497        if (fd->buffer_type == HFI_BUFFER_INPUT)
 498                return ops->session_etb(inst, fd);
 499        else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
 500                 fd->buffer_type == HFI_BUFFER_OUTPUT2)
 501                return ops->session_ftb(inst, fd);
 502
 503        return -EINVAL;
 504}
 505EXPORT_SYMBOL_GPL(hfi_session_process_buf);
 506
 507irqreturn_t hfi_isr_thread(int irq, void *dev_id)
 508{
 509        struct venus_core *core = dev_id;
 510
 511        return core->ops->isr_thread(core);
 512}
 513
 514irqreturn_t hfi_isr(int irq, void *dev)
 515{
 516        struct venus_core *core = dev;
 517
 518        return core->ops->isr(core);
 519}
 520
 521int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
 522{
 523        int ret;
 524
 525        if (!ops)
 526                return -EINVAL;
 527
 528        atomic_set(&core->insts_count, 0);
 529        core->core_ops = ops;
 530        core->state = CORE_UNINIT;
 531        init_completion(&core->done);
 532        pkt_set_version(core->res->hfi_version);
 533        ret = venus_hfi_create(core);
 534
 535        return ret;
 536}
 537
 538void hfi_destroy(struct venus_core *core)
 539{
 540        venus_hfi_destroy(core);
 541}
 542
 543void hfi_reinit(struct venus_core *core)
 544{
 545        venus_hfi_queues_reinit(core);
 546}
 547