1 /* 2 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. 3 * Copyright (C) 2017 Linaro Ltd. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 and 7 * only version 2 as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 #include <linux/slab.h> 16 #include <linux/mutex.h> 17 #include <linux/list.h> 18 #include <linux/completion.h> 19 #include <linux/platform_device.h> 20 #include <linux/videodev2.h> 21 22 #include "core.h" 23 #include "hfi.h" 24 #include "hfi_cmds.h" 25 #include "hfi_venus.h" 26 27 #define TIMEOUT msecs_to_jiffies(1000) 28 29 static u32 to_codec_type(u32 pixfmt) 30 { 31 switch (pixfmt) { 32 case V4L2_PIX_FMT_H264: 33 case V4L2_PIX_FMT_H264_NO_SC: 34 return HFI_VIDEO_CODEC_H264; 35 case V4L2_PIX_FMT_H263: 36 return HFI_VIDEO_CODEC_H263; 37 case V4L2_PIX_FMT_MPEG1: 38 return HFI_VIDEO_CODEC_MPEG1; 39 case V4L2_PIX_FMT_MPEG2: 40 return HFI_VIDEO_CODEC_MPEG2; 41 case V4L2_PIX_FMT_MPEG4: 42 return HFI_VIDEO_CODEC_MPEG4; 43 case V4L2_PIX_FMT_VC1_ANNEX_G: 44 case V4L2_PIX_FMT_VC1_ANNEX_L: 45 return HFI_VIDEO_CODEC_VC1; 46 case V4L2_PIX_FMT_VP8: 47 return HFI_VIDEO_CODEC_VP8; 48 case V4L2_PIX_FMT_VP9: 49 return HFI_VIDEO_CODEC_VP9; 50 case V4L2_PIX_FMT_XVID: 51 return HFI_VIDEO_CODEC_DIVX; 52 case V4L2_PIX_FMT_HEVC: 53 return HFI_VIDEO_CODEC_HEVC; 54 default: 55 return 0; 56 } 57 } 58 59 int hfi_core_init(struct venus_core *core) 60 { 61 int ret = 0; 62 63 mutex_lock(&core->lock); 64 65 if (core->state >= CORE_INIT) 66 goto unlock; 67 68 reinit_completion(&core->done); 69 70 ret = core->ops->core_init(core); 71 if (ret) 72 goto unlock; 73 74 ret = wait_for_completion_timeout(&core->done, TIMEOUT); 75 if (!ret) { 76 ret = -ETIMEDOUT; 77 goto unlock; 78 } 79 80 ret = 0; 81 82 if (core->error != HFI_ERR_NONE) { 83 ret = -EIO; 84 goto unlock; 85 } 86 87 core->state = CORE_INIT; 88 unlock: 89 mutex_unlock(&core->lock); 90 return ret; 91 } 92 93 int hfi_core_deinit(struct venus_core *core, bool blocking) 94 { 95 int ret = 0, empty; 96 97 mutex_lock(&core->lock); 98 99 if (core->state == CORE_UNINIT) 100 goto unlock; 101 102 empty = list_empty(&core->instances); 103 104 if (!empty && !blocking) { 105 ret = -EBUSY; 106 goto unlock; 107 } 108 109 if (!empty) { 110 mutex_unlock(&core->lock); 111 wait_var_event(&core->insts_count, 112 !atomic_read(&core->insts_count)); 113 mutex_lock(&core->lock); 114 } 115 116 ret = core->ops->core_deinit(core); 117 118 if (!ret) 119 core->state = CORE_UNINIT; 120 121 unlock: 122 mutex_unlock(&core->lock); 123 return ret; 124 } 125 126 int hfi_core_suspend(struct venus_core *core) 127 { 128 if (core->state != CORE_INIT) 129 return 0; 130 131 return core->ops->suspend(core); 132 } 133 134 int hfi_core_resume(struct venus_core *core, bool force) 135 { 136 if (!force && core->state != CORE_INIT) 137 return 0; 138 139 return core->ops->resume(core); 140 } 141 142 int hfi_core_trigger_ssr(struct venus_core *core, u32 type) 143 { 144 return core->ops->core_trigger_ssr(core, type); 145 } 146 147 int hfi_core_ping(struct venus_core *core) 148 { 149 int ret; 150 151 mutex_lock(&core->lock); 152 153 ret = core->ops->core_ping(core, 0xbeef); 154 if (ret) 155 goto unlock; 156 157 ret = wait_for_completion_timeout(&core->done, TIMEOUT); 158 if (!ret) { 159 ret = -ETIMEDOUT; 160 goto unlock; 161 } 162 ret = 0; 163 if (core->error != HFI_ERR_NONE) 164 ret = -ENODEV; 165 unlock: 166 mutex_unlock(&core->lock); 167 return ret; 168 } 169 170 static int wait_session_msg(struct venus_inst *inst) 171 { 172 int ret; 173 174 ret = wait_for_completion_timeout(&inst->done, TIMEOUT); 175 if (!ret) 176 return -ETIMEDOUT; 177 178 if (inst->error != HFI_ERR_NONE) 179 return -EIO; 180 181 return 0; 182 } 183 184 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops) 185 { 186 struct venus_core *core = inst->core; 187 188 if (!ops) 189 return -EINVAL; 190 191 inst->state = INST_UNINIT; 192 init_completion(&inst->done); 193 inst->ops = ops; 194 195 mutex_lock(&core->lock); 196 list_add_tail(&inst->list, &core->instances); 197 atomic_inc(&core->insts_count); 198 mutex_unlock(&core->lock); 199 200 return 0; 201 } 202 EXPORT_SYMBOL_GPL(hfi_session_create); 203 204 int hfi_session_init(struct venus_inst *inst, u32 pixfmt) 205 { 206 struct venus_core *core = inst->core; 207 const struct hfi_ops *ops = core->ops; 208 int ret; 209 210 inst->hfi_codec = to_codec_type(pixfmt); 211 reinit_completion(&inst->done); 212 213 ret = ops->session_init(inst, inst->session_type, inst->hfi_codec); 214 if (ret) 215 return ret; 216 217 ret = wait_session_msg(inst); 218 if (ret) 219 return ret; 220 221 inst->state = INST_INIT; 222 223 return 0; 224 } 225 EXPORT_SYMBOL_GPL(hfi_session_init); 226 227 void hfi_session_destroy(struct venus_inst *inst) 228 { 229 struct venus_core *core = inst->core; 230 231 mutex_lock(&core->lock); 232 list_del_init(&inst->list); 233 if (atomic_dec_and_test(&core->insts_count)) 234 wake_up_var(&core->insts_count); 235 mutex_unlock(&core->lock); 236 } 237 EXPORT_SYMBOL_GPL(hfi_session_destroy); 238 239 int hfi_session_deinit(struct venus_inst *inst) 240 { 241 const struct hfi_ops *ops = inst->core->ops; 242 int ret; 243 244 if (inst->state == INST_UNINIT) 245 return 0; 246 247 if (inst->state < INST_INIT) 248 return -EINVAL; 249 250 reinit_completion(&inst->done); 251 252 ret = ops->session_end(inst); 253 if (ret) 254 return ret; 255 256 ret = wait_session_msg(inst); 257 if (ret) 258 return ret; 259 260 inst->state = INST_UNINIT; 261 262 return 0; 263 } 264 EXPORT_SYMBOL_GPL(hfi_session_deinit); 265 266 int hfi_session_start(struct venus_inst *inst) 267 { 268 const struct hfi_ops *ops = inst->core->ops; 269 int ret; 270 271 if (inst->state != INST_LOAD_RESOURCES) 272 return -EINVAL; 273 274 reinit_completion(&inst->done); 275 276 ret = ops->session_start(inst); 277 if (ret) 278 return ret; 279 280 ret = wait_session_msg(inst); 281 if (ret) 282 return ret; 283 284 inst->state = INST_START; 285 286 return 0; 287 } 288 289 int hfi_session_stop(struct venus_inst *inst) 290 { 291 const struct hfi_ops *ops = inst->core->ops; 292 int ret; 293 294 if (inst->state != INST_START) 295 return -EINVAL; 296 297 reinit_completion(&inst->done); 298 299 ret = ops->session_stop(inst); 300 if (ret) 301 return ret; 302 303 ret = wait_session_msg(inst); 304 if (ret) 305 return ret; 306 307 inst->state = INST_STOP; 308 309 return 0; 310 } 311 312 int hfi_session_continue(struct venus_inst *inst) 313 { 314 struct venus_core *core = inst->core; 315 316 if (core->res->hfi_version == HFI_VERSION_1XX) 317 return 0; 318 319 return core->ops->session_continue(inst); 320 } 321 EXPORT_SYMBOL_GPL(hfi_session_continue); 322 323 int hfi_session_abort(struct venus_inst *inst) 324 { 325 const struct hfi_ops *ops = inst->core->ops; 326 int ret; 327 328 reinit_completion(&inst->done); 329 330 ret = ops->session_abort(inst); 331 if (ret) 332 return ret; 333 334 ret = wait_session_msg(inst); 335 if (ret) 336 return ret; 337 338 return 0; 339 } 340 341 int 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 364 int 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 } 386 387 int hfi_session_flush(struct venus_inst *inst) 388 { 389 const struct hfi_ops *ops = inst->core->ops; 390 int ret; 391 392 reinit_completion(&inst->done); 393 394 ret = ops->session_flush(inst, HFI_FLUSH_ALL); 395 if (ret) 396 return ret; 397 398 ret = wait_session_msg(inst); 399 if (ret) 400 return ret; 401 402 return 0; 403 } 404 EXPORT_SYMBOL_GPL(hfi_session_flush); 405 406 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd) 407 { 408 const struct hfi_ops *ops = inst->core->ops; 409 410 return ops->session_set_buffers(inst, bd); 411 } 412 413 int hfi_session_unset_buffers(struct venus_inst *inst, 414 struct hfi_buffer_desc *bd) 415 { 416 const struct hfi_ops *ops = inst->core->ops; 417 int ret; 418 419 reinit_completion(&inst->done); 420 421 ret = ops->session_unset_buffers(inst, bd); 422 if (ret) 423 return ret; 424 425 if (!bd->response_required) 426 return 0; 427 428 ret = wait_session_msg(inst); 429 if (ret) 430 return ret; 431 432 return 0; 433 } 434 435 int hfi_session_get_property(struct venus_inst *inst, u32 ptype, 436 union hfi_get_property *hprop) 437 { 438 const struct hfi_ops *ops = inst->core->ops; 439 int ret; 440 441 if (inst->state < INST_INIT || inst->state >= INST_STOP) 442 return -EINVAL; 443 444 reinit_completion(&inst->done); 445 446 ret = ops->session_get_property(inst, ptype); 447 if (ret) 448 return ret; 449 450 ret = wait_session_msg(inst); 451 if (ret) 452 return ret; 453 454 *hprop = inst->hprop; 455 456 return 0; 457 } 458 EXPORT_SYMBOL_GPL(hfi_session_get_property); 459 460 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata) 461 { 462 const struct hfi_ops *ops = inst->core->ops; 463 464 if (inst->state < INST_INIT || inst->state >= INST_STOP) 465 return -EINVAL; 466 467 return ops->session_set_property(inst, ptype, pdata); 468 } 469 EXPORT_SYMBOL_GPL(hfi_session_set_property); 470 471 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) 472 { 473 const struct hfi_ops *ops = inst->core->ops; 474 475 if (fd->buffer_type == HFI_BUFFER_INPUT) 476 return ops->session_etb(inst, fd); 477 else if (fd->buffer_type == HFI_BUFFER_OUTPUT || 478 fd->buffer_type == HFI_BUFFER_OUTPUT2) 479 return ops->session_ftb(inst, fd); 480 481 return -EINVAL; 482 } 483 EXPORT_SYMBOL_GPL(hfi_session_process_buf); 484 485 irqreturn_t hfi_isr_thread(int irq, void *dev_id) 486 { 487 struct venus_core *core = dev_id; 488 489 return core->ops->isr_thread(core); 490 } 491 492 irqreturn_t hfi_isr(int irq, void *dev) 493 { 494 struct venus_core *core = dev; 495 496 return core->ops->isr(core); 497 } 498 499 int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops) 500 { 501 int ret; 502 503 if (!ops) 504 return -EINVAL; 505 506 atomic_set(&core->insts_count, 0); 507 core->core_ops = ops; 508 core->state = CORE_UNINIT; 509 init_completion(&core->done); 510 pkt_set_version(core->res->hfi_version); 511 ret = venus_hfi_create(core); 512 513 return ret; 514 } 515 516 void hfi_destroy(struct venus_core *core) 517 { 518 venus_hfi_destroy(core); 519 } 520