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