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