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 default: 53 return 0; 54 } 55 } 56 57 int hfi_core_init(struct venus_core *core) 58 { 59 int ret = 0; 60 61 mutex_lock(&core->lock); 62 63 if (core->state >= CORE_INIT) 64 goto unlock; 65 66 reinit_completion(&core->done); 67 68 ret = core->ops->core_init(core); 69 if (ret) 70 goto unlock; 71 72 ret = wait_for_completion_timeout(&core->done, TIMEOUT); 73 if (!ret) { 74 ret = -ETIMEDOUT; 75 goto unlock; 76 } 77 78 ret = 0; 79 80 if (core->error != HFI_ERR_NONE) { 81 ret = -EIO; 82 goto unlock; 83 } 84 85 core->state = CORE_INIT; 86 unlock: 87 mutex_unlock(&core->lock); 88 return ret; 89 } 90 91 static int core_deinit_wait_atomic_t(atomic_t *p) 92 { 93 schedule(); 94 return 0; 95 } 96 97 int hfi_core_deinit(struct venus_core *core, bool blocking) 98 { 99 int ret = 0, empty; 100 101 mutex_lock(&core->lock); 102 103 if (core->state == CORE_UNINIT) 104 goto unlock; 105 106 empty = list_empty(&core->instances); 107 108 if (!empty && !blocking) { 109 ret = -EBUSY; 110 goto unlock; 111 } 112 113 if (!empty) { 114 mutex_unlock(&core->lock); 115 wait_on_atomic_t(&core->insts_count, core_deinit_wait_atomic_t, 116 TASK_UNINTERRUPTIBLE); 117 mutex_lock(&core->lock); 118 } 119 120 ret = core->ops->core_deinit(core); 121 122 if (!ret) 123 core->state = CORE_UNINIT; 124 125 unlock: 126 mutex_unlock(&core->lock); 127 return ret; 128 } 129 130 int hfi_core_suspend(struct venus_core *core) 131 { 132 if (core->state != CORE_INIT) 133 return 0; 134 135 return core->ops->suspend(core); 136 } 137 138 int hfi_core_resume(struct venus_core *core, bool force) 139 { 140 if (!force && core->state != CORE_INIT) 141 return 0; 142 143 return core->ops->resume(core); 144 } 145 146 int hfi_core_trigger_ssr(struct venus_core *core, u32 type) 147 { 148 return core->ops->core_trigger_ssr(core, type); 149 } 150 151 int hfi_core_ping(struct venus_core *core) 152 { 153 int ret; 154 155 mutex_lock(&core->lock); 156 157 ret = core->ops->core_ping(core, 0xbeef); 158 if (ret) 159 goto unlock; 160 161 ret = wait_for_completion_timeout(&core->done, TIMEOUT); 162 if (!ret) { 163 ret = -ETIMEDOUT; 164 goto unlock; 165 } 166 ret = 0; 167 if (core->error != HFI_ERR_NONE) 168 ret = -ENODEV; 169 unlock: 170 mutex_unlock(&core->lock); 171 return ret; 172 } 173 174 static int wait_session_msg(struct venus_inst *inst) 175 { 176 int ret; 177 178 ret = wait_for_completion_timeout(&inst->done, TIMEOUT); 179 if (!ret) 180 return -ETIMEDOUT; 181 182 if (inst->error != HFI_ERR_NONE) 183 return -EIO; 184 185 return 0; 186 } 187 188 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops) 189 { 190 struct venus_core *core = inst->core; 191 192 if (!ops) 193 return -EINVAL; 194 195 inst->state = INST_UNINIT; 196 init_completion(&inst->done); 197 inst->ops = ops; 198 199 mutex_lock(&core->lock); 200 list_add_tail(&inst->list, &core->instances); 201 atomic_inc(&core->insts_count); 202 mutex_unlock(&core->lock); 203 204 return 0; 205 } 206 EXPORT_SYMBOL_GPL(hfi_session_create); 207 208 int hfi_session_init(struct venus_inst *inst, u32 pixfmt) 209 { 210 struct venus_core *core = inst->core; 211 const struct hfi_ops *ops = core->ops; 212 u32 codec; 213 int ret; 214 215 codec = to_codec_type(pixfmt); 216 reinit_completion(&inst->done); 217 218 ret = ops->session_init(inst, inst->session_type, codec); 219 if (ret) 220 return ret; 221 222 ret = wait_session_msg(inst); 223 if (ret) 224 return ret; 225 226 inst->state = INST_INIT; 227 228 return 0; 229 } 230 EXPORT_SYMBOL_GPL(hfi_session_init); 231 232 void hfi_session_destroy(struct venus_inst *inst) 233 { 234 struct venus_core *core = inst->core; 235 236 mutex_lock(&core->lock); 237 list_del_init(&inst->list); 238 atomic_dec(&core->insts_count); 239 wake_up_atomic_t(&core->insts_count); 240 mutex_unlock(&core->lock); 241 } 242 EXPORT_SYMBOL_GPL(hfi_session_destroy); 243 244 int hfi_session_deinit(struct venus_inst *inst) 245 { 246 const struct hfi_ops *ops = inst->core->ops; 247 int ret; 248 249 if (inst->state == INST_UNINIT) 250 return 0; 251 252 if (inst->state < INST_INIT) 253 return -EINVAL; 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 inst->state = INST_UNINIT; 266 267 return 0; 268 } 269 EXPORT_SYMBOL_GPL(hfi_session_deinit); 270 271 int hfi_session_start(struct venus_inst *inst) 272 { 273 const struct hfi_ops *ops = inst->core->ops; 274 int ret; 275 276 if (inst->state != INST_LOAD_RESOURCES) 277 return -EINVAL; 278 279 reinit_completion(&inst->done); 280 281 ret = ops->session_start(inst); 282 if (ret) 283 return ret; 284 285 ret = wait_session_msg(inst); 286 if (ret) 287 return ret; 288 289 inst->state = INST_START; 290 291 return 0; 292 } 293 294 int hfi_session_stop(struct venus_inst *inst) 295 { 296 const struct hfi_ops *ops = inst->core->ops; 297 int ret; 298 299 if (inst->state != INST_START) 300 return -EINVAL; 301 302 reinit_completion(&inst->done); 303 304 ret = ops->session_stop(inst); 305 if (ret) 306 return ret; 307 308 ret = wait_session_msg(inst); 309 if (ret) 310 return ret; 311 312 inst->state = INST_STOP; 313 314 return 0; 315 } 316 317 int hfi_session_continue(struct venus_inst *inst) 318 { 319 struct venus_core *core = inst->core; 320 321 if (core->res->hfi_version != HFI_VERSION_3XX) 322 return 0; 323 324 return core->ops->session_continue(inst); 325 } 326 EXPORT_SYMBOL_GPL(hfi_session_continue); 327 328 int hfi_session_abort(struct venus_inst *inst) 329 { 330 const struct hfi_ops *ops = inst->core->ops; 331 int ret; 332 333 reinit_completion(&inst->done); 334 335 ret = ops->session_abort(inst); 336 if (ret) 337 return ret; 338 339 ret = wait_session_msg(inst); 340 if (ret) 341 return ret; 342 343 return 0; 344 } 345 346 int hfi_session_load_res(struct venus_inst *inst) 347 { 348 const struct hfi_ops *ops = inst->core->ops; 349 int ret; 350 351 if (inst->state != INST_INIT) 352 return -EINVAL; 353 354 reinit_completion(&inst->done); 355 356 ret = ops->session_load_res(inst); 357 if (ret) 358 return ret; 359 360 ret = wait_session_msg(inst); 361 if (ret) 362 return ret; 363 364 inst->state = INST_LOAD_RESOURCES; 365 366 return 0; 367 } 368 369 int hfi_session_unload_res(struct venus_inst *inst) 370 { 371 const struct hfi_ops *ops = inst->core->ops; 372 int ret; 373 374 if (inst->state != INST_STOP) 375 return -EINVAL; 376 377 reinit_completion(&inst->done); 378 379 ret = ops->session_release_res(inst); 380 if (ret) 381 return ret; 382 383 ret = wait_session_msg(inst); 384 if (ret) 385 return ret; 386 387 inst->state = INST_RELEASE_RESOURCES; 388 389 return 0; 390 } 391 392 int hfi_session_flush(struct venus_inst *inst) 393 { 394 const struct hfi_ops *ops = inst->core->ops; 395 int ret; 396 397 reinit_completion(&inst->done); 398 399 ret = ops->session_flush(inst, HFI_FLUSH_ALL); 400 if (ret) 401 return ret; 402 403 ret = wait_session_msg(inst); 404 if (ret) 405 return ret; 406 407 return 0; 408 } 409 EXPORT_SYMBOL_GPL(hfi_session_flush); 410 411 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd) 412 { 413 const struct hfi_ops *ops = inst->core->ops; 414 415 return ops->session_set_buffers(inst, bd); 416 } 417 418 int hfi_session_unset_buffers(struct venus_inst *inst, 419 struct hfi_buffer_desc *bd) 420 { 421 const struct hfi_ops *ops = inst->core->ops; 422 int ret; 423 424 reinit_completion(&inst->done); 425 426 ret = ops->session_unset_buffers(inst, bd); 427 if (ret) 428 return ret; 429 430 if (!bd->response_required) 431 return 0; 432 433 ret = wait_session_msg(inst); 434 if (ret) 435 return ret; 436 437 return 0; 438 } 439 440 int hfi_session_get_property(struct venus_inst *inst, u32 ptype, 441 union hfi_get_property *hprop) 442 { 443 const struct hfi_ops *ops = inst->core->ops; 444 int ret; 445 446 if (inst->state < INST_INIT || inst->state >= INST_STOP) 447 return -EINVAL; 448 449 reinit_completion(&inst->done); 450 451 ret = ops->session_get_property(inst, ptype); 452 if (ret) 453 return ret; 454 455 ret = wait_session_msg(inst); 456 if (ret) 457 return ret; 458 459 *hprop = inst->hprop; 460 461 return 0; 462 } 463 EXPORT_SYMBOL_GPL(hfi_session_get_property); 464 465 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata) 466 { 467 const struct hfi_ops *ops = inst->core->ops; 468 469 if (inst->state < INST_INIT || inst->state >= INST_STOP) 470 return -EINVAL; 471 472 return ops->session_set_property(inst, ptype, pdata); 473 } 474 EXPORT_SYMBOL_GPL(hfi_session_set_property); 475 476 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) 477 { 478 const struct hfi_ops *ops = inst->core->ops; 479 480 if (fd->buffer_type == HFI_BUFFER_INPUT) 481 return ops->session_etb(inst, fd); 482 else if (fd->buffer_type == HFI_BUFFER_OUTPUT) 483 return ops->session_ftb(inst, fd); 484 485 return -EINVAL; 486 } 487 488 irqreturn_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 495 irqreturn_t hfi_isr(int irq, void *dev) 496 { 497 struct venus_core *core = dev; 498 499 return core->ops->isr(core); 500 } 501 502 int 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 519 void hfi_destroy(struct venus_core *core) 520 { 521 venus_hfi_destroy(core); 522 } 523