brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · e00aedb Raw
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