593 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 if (!core->ops)108 goto unlock;109 110 ret = core->ops->core_deinit(core);111 112 if (!ret)113 core->state = CORE_UNINIT;114 115unlock:116 mutex_unlock(&core->lock);117 return ret;118}119 120int hfi_core_suspend(struct venus_core *core)121{122 if (core->state != CORE_INIT)123 return 0;124 125 return core->ops->suspend(core);126}127 128int hfi_core_resume(struct venus_core *core, bool force)129{130 if (!force && core->state != CORE_INIT)131 return 0;132 133 return core->ops->resume(core);134}135 136int hfi_core_trigger_ssr(struct venus_core *core, u32 type)137{138 return core->ops->core_trigger_ssr(core, type);139}140 141int hfi_core_ping(struct venus_core *core)142{143 int ret;144 145 mutex_lock(&core->lock);146 147 ret = core->ops->core_ping(core, 0xbeef);148 if (ret)149 goto unlock;150 151 ret = wait_for_completion_timeout(&core->done, TIMEOUT);152 if (!ret) {153 ret = -ETIMEDOUT;154 goto unlock;155 }156 ret = 0;157 if (core->error != HFI_ERR_NONE)158 ret = -ENODEV;159unlock:160 mutex_unlock(&core->lock);161 return ret;162}163 164static int wait_session_msg(struct venus_inst *inst)165{166 int ret;167 168 ret = wait_for_completion_timeout(&inst->done, TIMEOUT);169 if (!ret)170 return -ETIMEDOUT;171 172 if (inst->error != HFI_ERR_NONE)173 return -EIO;174 175 return 0;176}177 178int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)179{180 struct venus_core *core = inst->core;181 bool max;182 int ret;183 184 if (!ops)185 return -EINVAL;186 187 inst->state = INST_UNINIT;188 init_completion(&inst->done);189 inst->ops = ops;190 191 mutex_lock(&core->lock);192 193 if (test_bit(0, &inst->core->sys_error)) {194 ret = -EIO;195 goto unlock;196 }197 198 max = atomic_add_unless(&core->insts_count, 1,199 core->max_sessions_supported);200 if (!max) {201 ret = -EAGAIN;202 } else {203 list_add_tail(&inst->list, &core->instances);204 ret = 0;205 }206 207unlock:208 mutex_unlock(&core->lock);209 210 return ret;211}212EXPORT_SYMBOL_GPL(hfi_session_create);213 214int hfi_session_init(struct venus_inst *inst, u32 pixfmt)215{216 struct venus_core *core = inst->core;217 const struct hfi_ops *ops = core->ops;218 int ret;219 220 /*221 * If core shutdown is in progress or if we are in system222 * recovery, return an error as during system error recovery223 * session_init() can't pass successfully224 */225 mutex_lock(&core->lock);226 if (!core->ops || test_bit(0, &inst->core->sys_error)) {227 mutex_unlock(&core->lock);228 return -EIO;229 }230 mutex_unlock(&core->lock);231 232 if (inst->state != INST_UNINIT)233 return -EALREADY;234 235 inst->hfi_codec = to_codec_type(pixfmt);236 reinit_completion(&inst->done);237 238 ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);239 if (ret)240 return ret;241 242 ret = wait_session_msg(inst);243 if (ret)244 return ret;245 246 inst->state = INST_INIT;247 248 return 0;249}250EXPORT_SYMBOL_GPL(hfi_session_init);251 252void hfi_session_destroy(struct venus_inst *inst)253{254 struct venus_core *core = inst->core;255 256 mutex_lock(&core->lock);257 list_del_init(&inst->list);258 if (atomic_dec_and_test(&core->insts_count))259 wake_up_var(&core->insts_count);260 mutex_unlock(&core->lock);261}262EXPORT_SYMBOL_GPL(hfi_session_destroy);263 264int hfi_session_deinit(struct venus_inst *inst)265{266 const struct hfi_ops *ops = inst->core->ops;267 int ret;268 269 if (inst->state == INST_UNINIT)270 return 0;271 272 if (inst->state < INST_INIT)273 return -EINVAL;274 275 if (test_bit(0, &inst->core->sys_error))276 goto done;277 278 reinit_completion(&inst->done);279 280 ret = ops->session_end(inst);281 if (ret)282 return ret;283 284 ret = wait_session_msg(inst);285 if (ret)286 return ret;287 288done:289 inst->state = INST_UNINIT;290 291 return 0;292}293EXPORT_SYMBOL_GPL(hfi_session_deinit);294 295int hfi_session_start(struct venus_inst *inst)296{297 const struct hfi_ops *ops = inst->core->ops;298 int ret;299 300 if (test_bit(0, &inst->core->sys_error))301 return -EIO;302 303 if (inst->state != INST_LOAD_RESOURCES)304 return -EINVAL;305 306 reinit_completion(&inst->done);307 308 ret = ops->session_start(inst);309 if (ret)310 return ret;311 312 ret = wait_session_msg(inst);313 if (ret)314 return ret;315 316 inst->state = INST_START;317 318 return 0;319}320EXPORT_SYMBOL_GPL(hfi_session_start);321 322int hfi_session_stop(struct venus_inst *inst)323{324 const struct hfi_ops *ops = inst->core->ops;325 int ret;326 327 if (test_bit(0, &inst->core->sys_error))328 return -EIO;329 330 if (inst->state != INST_START)331 return -EINVAL;332 333 reinit_completion(&inst->done);334 335 ret = ops->session_stop(inst);336 if (ret)337 return ret;338 339 ret = wait_session_msg(inst);340 if (ret)341 return ret;342 343 inst->state = INST_STOP;344 345 return 0;346}347EXPORT_SYMBOL_GPL(hfi_session_stop);348 349int hfi_session_continue(struct venus_inst *inst)350{351 struct venus_core *core = inst->core;352 353 if (test_bit(0, &inst->core->sys_error))354 return -EIO;355 356 if (core->res->hfi_version == HFI_VERSION_1XX)357 return 0;358 359 return core->ops->session_continue(inst);360}361EXPORT_SYMBOL_GPL(hfi_session_continue);362 363int hfi_session_abort(struct venus_inst *inst)364{365 const struct hfi_ops *ops = inst->core->ops;366 int ret;367 368 if (test_bit(0, &inst->core->sys_error))369 return -EIO;370 371 reinit_completion(&inst->done);372 373 ret = ops->session_abort(inst);374 if (ret)375 return ret;376 377 ret = wait_session_msg(inst);378 if (ret)379 return ret;380 381 return 0;382}383EXPORT_SYMBOL_GPL(hfi_session_abort);384 385int hfi_session_load_res(struct venus_inst *inst)386{387 const struct hfi_ops *ops = inst->core->ops;388 int ret;389 390 if (test_bit(0, &inst->core->sys_error))391 return -EIO;392 393 if (inst->state != INST_INIT)394 return -EINVAL;395 396 reinit_completion(&inst->done);397 398 ret = ops->session_load_res(inst);399 if (ret)400 return ret;401 402 ret = wait_session_msg(inst);403 if (ret)404 return ret;405 406 inst->state = INST_LOAD_RESOURCES;407 408 return 0;409}410 411int hfi_session_unload_res(struct venus_inst *inst)412{413 const struct hfi_ops *ops = inst->core->ops;414 int ret;415 416 if (test_bit(0, &inst->core->sys_error))417 return -EIO;418 419 if (inst->state != INST_STOP)420 return -EINVAL;421 422 reinit_completion(&inst->done);423 424 ret = ops->session_release_res(inst);425 if (ret)426 return ret;427 428 ret = wait_session_msg(inst);429 if (ret)430 return ret;431 432 inst->state = INST_RELEASE_RESOURCES;433 434 return 0;435}436EXPORT_SYMBOL_GPL(hfi_session_unload_res);437 438int hfi_session_flush(struct venus_inst *inst, u32 type, bool block)439{440 const struct hfi_ops *ops = inst->core->ops;441 int ret;442 443 if (test_bit(0, &inst->core->sys_error))444 return -EIO;445 446 reinit_completion(&inst->done);447 448 ret = ops->session_flush(inst, type);449 if (ret)450 return ret;451 452 if (block) {453 ret = wait_session_msg(inst);454 if (ret)455 return ret;456 }457 458 return 0;459}460EXPORT_SYMBOL_GPL(hfi_session_flush);461 462int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)463{464 const struct hfi_ops *ops = inst->core->ops;465 466 if (test_bit(0, &inst->core->sys_error))467 return -EIO;468 469 return ops->session_set_buffers(inst, bd);470}471 472int hfi_session_unset_buffers(struct venus_inst *inst,473 struct hfi_buffer_desc *bd)474{475 const struct hfi_ops *ops = inst->core->ops;476 int ret;477 478 if (test_bit(0, &inst->core->sys_error))479 return -EIO;480 481 reinit_completion(&inst->done);482 483 ret = ops->session_unset_buffers(inst, bd);484 if (ret)485 return ret;486 487 if (!bd->response_required)488 return 0;489 490 ret = wait_session_msg(inst);491 if (ret)492 return ret;493 494 return 0;495}496 497int hfi_session_get_property(struct venus_inst *inst, u32 ptype,498 union hfi_get_property *hprop)499{500 const struct hfi_ops *ops = inst->core->ops;501 int ret;502 503 if (test_bit(0, &inst->core->sys_error))504 return -EIO;505 506 if (inst->state < INST_INIT || inst->state >= INST_STOP)507 return -EINVAL;508 509 reinit_completion(&inst->done);510 511 ret = ops->session_get_property(inst, ptype);512 if (ret)513 return ret;514 515 ret = wait_session_msg(inst);516 if (ret)517 return ret;518 519 *hprop = inst->hprop;520 521 return 0;522}523EXPORT_SYMBOL_GPL(hfi_session_get_property);524 525int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)526{527 const struct hfi_ops *ops = inst->core->ops;528 529 if (test_bit(0, &inst->core->sys_error))530 return -EIO;531 532 if (inst->state < INST_INIT || inst->state >= INST_STOP)533 return -EINVAL;534 535 return ops->session_set_property(inst, ptype, pdata);536}537EXPORT_SYMBOL_GPL(hfi_session_set_property);538 539int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)540{541 const struct hfi_ops *ops = inst->core->ops;542 543 if (test_bit(0, &inst->core->sys_error))544 return -EIO;545 546 if (fd->buffer_type == HFI_BUFFER_INPUT)547 return ops->session_etb(inst, fd);548 else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||549 fd->buffer_type == HFI_BUFFER_OUTPUT2)550 return ops->session_ftb(inst, fd);551 552 return -EINVAL;553}554EXPORT_SYMBOL_GPL(hfi_session_process_buf);555 556irqreturn_t hfi_isr_thread(int irq, void *dev_id)557{558 struct venus_core *core = dev_id;559 560 return core->ops->isr_thread(core);561}562 563irqreturn_t hfi_isr(int irq, void *dev)564{565 struct venus_core *core = dev;566 567 return core->ops->isr(core);568}569 570int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)571{572 if (!ops)573 return -EINVAL;574 575 atomic_set(&core->insts_count, 0);576 core->core_ops = ops;577 core->state = CORE_UNINIT;578 init_completion(&core->done);579 pkt_set_version(core->res->hfi_version);580 581 return venus_hfi_create(core);582}583 584void hfi_destroy(struct venus_core *core)585{586 venus_hfi_destroy(core);587}588 589void hfi_reinit(struct venus_core *core)590{591 venus_hfi_queues_reinit(core);592}593