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
 179        if (!ops)
 180                return -EINVAL;
 181
 182        inst->state = INST_UNINIT;
 183        init_completion(&inst->done);
 184        inst->ops = ops;
 185
 186        mutex_lock(&core->lock);
 187        list_add_tail(&inst->list, &core->instances);
 188        atomic_inc(&core->insts_count);
 189        mutex_unlock(&core->lock);
 190
 191        return 0;
 192}
 193EXPORT_SYMBOL_GPL(hfi_session_create);
 194
 195int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
 196{
 197        struct venus_core *core = inst->core;
 198        const struct hfi_ops *ops = core->ops;
 199        int ret;
 200
 201        if (inst->state != INST_UNINIT)
 202                return -EINVAL;
 203
 204        inst->hfi_codec = to_codec_type(pixfmt);
 205        reinit_completion(&inst->done);
 206
 207        ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
 208        if (ret)
 209                return ret;
 210
 211        ret = wait_session_msg(inst);
 212        if (ret)
 213                return ret;
 214
 215        inst->state = INST_INIT;
 216
 217        return 0;
 218}
 219EXPORT_SYMBOL_GPL(hfi_session_init);
 220
 221void hfi_session_destroy(struct venus_inst *inst)
 222{
 223        struct venus_core *core = inst->core;
 224
 225        mutex_lock(&core->lock);
 226        list_del_init(&inst->list);
 227        if (atomic_dec_and_test(&core->insts_count))
 228                wake_up_var(&core->insts_count);
 229        mutex_unlock(&core->lock);
 230}
 231EXPORT_SYMBOL_GPL(hfi_session_destroy);
 232
 233int hfi_session_deinit(struct venus_inst *inst)
 234{
 235        const struct hfi_ops *ops = inst->core->ops;
 236        int ret;
 237
 238        if (inst->state == INST_UNINIT)
 239                return 0;
 240
 241        if (inst->state < INST_INIT)
 242                return -EINVAL;
 243
 244        reinit_completion(&inst->done);
 245
 246        ret = ops->session_end(inst);
 247        if (ret)
 248                return ret;
 249
 250        ret = wait_session_msg(inst);
 251        if (ret)
 252                return ret;
 253
 254        inst->state = INST_UNINIT;
 255
 256        return 0;
 257}
 258EXPORT_SYMBOL_GPL(hfi_session_deinit);
 259
 260int hfi_session_start(struct venus_inst *inst)
 261{
 262        const struct hfi_ops *ops = inst->core->ops;
 263        int ret;
 264
 265        if (inst->state != INST_LOAD_RESOURCES)
 266                return -EINVAL;
 267
 268        reinit_completion(&inst->done);
 269
 270        ret = ops->session_start(inst);
 271        if (ret)
 272                return ret;
 273
 274        ret = wait_session_msg(inst);
 275        if (ret)
 276                return ret;
 277
 278        inst->state = INST_START;
 279
 280        return 0;
 281}
 282EXPORT_SYMBOL_GPL(hfi_session_start);
 283
 284int hfi_session_stop(struct venus_inst *inst)
 285{
 286        const struct hfi_ops *ops = inst->core->ops;
 287        int ret;
 288
 289        if (inst->state != INST_START)
 290                return -EINVAL;
 291
 292        reinit_completion(&inst->done);
 293
 294        ret = ops->session_stop(inst);
 295        if (ret)
 296                return ret;
 297
 298        ret = wait_session_msg(inst);
 299        if (ret)
 300                return ret;
 301
 302        inst->state = INST_STOP;
 303
 304        return 0;
 305}
 306EXPORT_SYMBOL_GPL(hfi_session_stop);
 307
 308int hfi_session_continue(struct venus_inst *inst)
 309{
 310        struct venus_core *core = inst->core;
 311
 312        if (core->res->hfi_version == HFI_VERSION_1XX)
 313                return 0;
 314
 315        return core->ops->session_continue(inst);
 316}
 317EXPORT_SYMBOL_GPL(hfi_session_continue);
 318
 319int hfi_session_abort(struct venus_inst *inst)
 320{
 321        const struct hfi_ops *ops = inst->core->ops;
 322        int ret;
 323
 324        reinit_completion(&inst->done);
 325
 326        ret = ops->session_abort(inst);
 327        if (ret)
 328                return ret;
 329
 330        ret = wait_session_msg(inst);
 331        if (ret)
 332                return ret;
 333
 334        return 0;
 335}
 336EXPORT_SYMBOL_GPL(hfi_session_abort);
 337
 338int hfi_session_load_res(struct venus_inst *inst)
 339{
 340        const struct hfi_ops *ops = inst->core->ops;
 341        int ret;
 342
 343        if (inst->state != INST_INIT)
 344                return -EINVAL;
 345
 346        reinit_completion(&inst->done);
 347
 348        ret = ops->session_load_res(inst);
 349        if (ret)
 350                return ret;
 351
 352        ret = wait_session_msg(inst);
 353        if (ret)
 354                return ret;
 355
 356        inst->state = INST_LOAD_RESOURCES;
 357
 358        return 0;
 359}
 360
 361int hfi_session_unload_res(struct venus_inst *inst)
 362{
 363        const struct hfi_ops *ops = inst->core->ops;
 364        int ret;
 365
 366        if (inst->state != INST_STOP)
 367                return -EINVAL;
 368
 369        reinit_completion(&inst->done);
 370
 371        ret = ops->session_release_res(inst);
 372        if (ret)
 373                return ret;
 374
 375        ret = wait_session_msg(inst);
 376        if (ret)
 377                return ret;
 378
 379        inst->state = INST_RELEASE_RESOURCES;
 380
 381        return 0;
 382}
 383EXPORT_SYMBOL_GPL(hfi_session_unload_res);
 384
 385int hfi_session_flush(struct venus_inst *inst, u32 type)
 386{
 387        const struct hfi_ops *ops = inst->core->ops;
 388        int ret;
 389
 390        reinit_completion(&inst->done);
 391
 392        ret = ops->session_flush(inst, type);
 393        if (ret)
 394                return ret;
 395
 396        ret = wait_session_msg(inst);
 397        if (ret)
 398                return ret;
 399
 400        return 0;
 401}
 402EXPORT_SYMBOL_GPL(hfi_session_flush);
 403
 404int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
 405{
 406        const struct hfi_ops *ops = inst->core->ops;
 407
 408        return ops->session_set_buffers(inst, bd);
 409}
 410
 411int hfi_session_unset_buffers(struct venus_inst *inst,
 412                              struct hfi_buffer_desc *bd)
 413{
 414        const struct hfi_ops *ops = inst->core->ops;
 415        int ret;
 416
 417        reinit_completion(&inst->done);
 418
 419        ret = ops->session_unset_buffers(inst, bd);
 420        if (ret)
 421                return ret;
 422
 423        if (!bd->response_required)
 424                return 0;
 425
 426        ret = wait_session_msg(inst);
 427        if (ret)
 428                return ret;
 429
 430        return 0;
 431}
 432
 433int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
 434                             union hfi_get_property *hprop)
 435{
 436        const struct hfi_ops *ops = inst->core->ops;
 437        int ret;
 438
 439        if (inst->state < INST_INIT || inst->state >= INST_STOP)
 440                return -EINVAL;
 441
 442        reinit_completion(&inst->done);
 443
 444        ret = ops->session_get_property(inst, ptype);
 445        if (ret)
 446                return ret;
 447
 448        ret = wait_session_msg(inst);
 449        if (ret)
 450                return ret;
 451
 452        *hprop = inst->hprop;
 453
 454        return 0;
 455}
 456EXPORT_SYMBOL_GPL(hfi_session_get_property);
 457
 458int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
 459{
 460        const struct hfi_ops *ops = inst->core->ops;
 461
 462        if (inst->state < INST_INIT || inst->state >= INST_STOP)
 463                return -EINVAL;
 464
 465        return ops->session_set_property(inst, ptype, pdata);
 466}
 467EXPORT_SYMBOL_GPL(hfi_session_set_property);
 468
 469int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
 470{
 471        const struct hfi_ops *ops = inst->core->ops;
 472
 473        if (fd->buffer_type == HFI_BUFFER_INPUT)
 474                return ops->session_etb(inst, fd);
 475        else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
 476                 fd->buffer_type == HFI_BUFFER_OUTPUT2)
 477                return ops->session_ftb(inst, fd);
 478
 479        return -EINVAL;
 480}
 481EXPORT_SYMBOL_GPL(hfi_session_process_buf);
 482
 483irqreturn_t hfi_isr_thread(int irq, void *dev_id)
 484{
 485        struct venus_core *core = dev_id;
 486
 487        return core->ops->isr_thread(core);
 488}
 489
 490irqreturn_t hfi_isr(int irq, void *dev)
 491{
 492        struct venus_core *core = dev;
 493
 494        return core->ops->isr(core);
 495}
 496
 497int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
 498{
 499        int ret;
 500
 501        if (!ops)
 502                return -EINVAL;
 503
 504        atomic_set(&core->insts_count, 0);
 505        core->core_ops = ops;
 506        core->state = CORE_UNINIT;
 507        init_completion(&core->done);
 508        pkt_set_version(core->res->hfi_version);
 509        ret = venus_hfi_create(core);
 510
 511        return ret;
 512}
 513
 514void hfi_destroy(struct venus_core *core)
 515{
 516        venus_hfi_destroy(core);
 517}
 518