162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2020-2021 NXP
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/interconnect.h>
862306a36Sopenharmony_ci#include <linux/ioctl.h>
962306a36Sopenharmony_ci#include <linux/list.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/vmalloc.h>
1762306a36Sopenharmony_ci#include "vpu.h"
1862306a36Sopenharmony_ci#include "vpu_defs.h"
1962306a36Sopenharmony_ci#include "vpu_cmds.h"
2062306a36Sopenharmony_ci#include "vpu_rpc.h"
2162306a36Sopenharmony_ci#include "vpu_mbox.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct vpu_cmd_request {
2462306a36Sopenharmony_ci	u32 request;
2562306a36Sopenharmony_ci	u32 response;
2662306a36Sopenharmony_ci	u32 handled;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct vpu_cmd_t {
3062306a36Sopenharmony_ci	struct list_head list;
3162306a36Sopenharmony_ci	u32 id;
3262306a36Sopenharmony_ci	struct vpu_cmd_request *request;
3362306a36Sopenharmony_ci	struct vpu_rpc_event *pkt;
3462306a36Sopenharmony_ci	unsigned long key;
3562306a36Sopenharmony_ci	atomic_long_t *last_response_cmd;
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic struct vpu_cmd_request vpu_cmd_requests[] = {
3962306a36Sopenharmony_ci	{
4062306a36Sopenharmony_ci		.request = VPU_CMD_ID_CONFIGURE_CODEC,
4162306a36Sopenharmony_ci		.response = VPU_MSG_ID_MEM_REQUEST,
4262306a36Sopenharmony_ci		.handled = 1,
4362306a36Sopenharmony_ci	},
4462306a36Sopenharmony_ci	{
4562306a36Sopenharmony_ci		.request = VPU_CMD_ID_START,
4662306a36Sopenharmony_ci		.response = VPU_MSG_ID_START_DONE,
4762306a36Sopenharmony_ci		.handled = 0,
4862306a36Sopenharmony_ci	},
4962306a36Sopenharmony_ci	{
5062306a36Sopenharmony_ci		.request = VPU_CMD_ID_STOP,
5162306a36Sopenharmony_ci		.response = VPU_MSG_ID_STOP_DONE,
5262306a36Sopenharmony_ci		.handled = 0,
5362306a36Sopenharmony_ci	},
5462306a36Sopenharmony_ci	{
5562306a36Sopenharmony_ci		.request = VPU_CMD_ID_ABORT,
5662306a36Sopenharmony_ci		.response = VPU_MSG_ID_ABORT_DONE,
5762306a36Sopenharmony_ci		.handled = 0,
5862306a36Sopenharmony_ci	},
5962306a36Sopenharmony_ci	{
6062306a36Sopenharmony_ci		.request = VPU_CMD_ID_RST_BUF,
6162306a36Sopenharmony_ci		.response = VPU_MSG_ID_BUF_RST,
6262306a36Sopenharmony_ci		.handled = 1,
6362306a36Sopenharmony_ci	},
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int vpu_cmd_send(struct vpu_core *core, struct vpu_rpc_event *pkt)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	int ret = 0;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = vpu_iface_send_cmd(core, pkt);
7162306a36Sopenharmony_ci	if (ret)
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/*write cmd data to cmd buffer before trigger a cmd interrupt*/
7562306a36Sopenharmony_ci	mb();
7662306a36Sopenharmony_ci	vpu_mbox_send_type(core, COMMAND);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return ret;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct vpu_cmd_t *cmd;
8462306a36Sopenharmony_ci	int i;
8562306a36Sopenharmony_ci	int ret;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	cmd = vzalloc(sizeof(*cmd));
8862306a36Sopenharmony_ci	if (!cmd)
8962306a36Sopenharmony_ci		return NULL;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	cmd->pkt = vzalloc(sizeof(*cmd->pkt));
9262306a36Sopenharmony_ci	if (!cmd->pkt) {
9362306a36Sopenharmony_ci		vfree(cmd);
9462306a36Sopenharmony_ci		return NULL;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	cmd->id = id;
9862306a36Sopenharmony_ci	ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data);
9962306a36Sopenharmony_ci	if (ret) {
10062306a36Sopenharmony_ci		dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id));
10162306a36Sopenharmony_ci		vfree(cmd->pkt);
10262306a36Sopenharmony_ci		vfree(cmd);
10362306a36Sopenharmony_ci		return NULL;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vpu_cmd_requests); i++) {
10662306a36Sopenharmony_ci		if (vpu_cmd_requests[i].request == id) {
10762306a36Sopenharmony_ci			cmd->request = &vpu_cmd_requests[i];
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return cmd;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic void vpu_free_cmd(struct vpu_cmd_t *cmd)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	if (!cmd)
11862306a36Sopenharmony_ci		return;
11962306a36Sopenharmony_ci	if (cmd->last_response_cmd)
12062306a36Sopenharmony_ci		atomic_long_set(cmd->last_response_cmd, cmd->key);
12162306a36Sopenharmony_ci	vfree(cmd->pkt);
12262306a36Sopenharmony_ci	vfree(cmd);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int ret;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	dev_dbg(inst->dev, "[%d]send cmd %s\n", inst->id, vpu_id_name(cmd->id));
13062306a36Sopenharmony_ci	vpu_iface_pre_send_cmd(inst);
13162306a36Sopenharmony_ci	ret = vpu_cmd_send(inst->core, cmd->pkt);
13262306a36Sopenharmony_ci	if (!ret) {
13362306a36Sopenharmony_ci		vpu_iface_post_send_cmd(inst);
13462306a36Sopenharmony_ci		vpu_inst_record_flow(inst, cmd->id);
13562306a36Sopenharmony_ci	} else {
13662306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] iface send cmd %s fail\n", inst->id, vpu_id_name(cmd->id));
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return ret;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void vpu_process_cmd_request(struct vpu_inst *inst)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct vpu_cmd_t *cmd;
14562306a36Sopenharmony_ci	struct vpu_cmd_t *tmp;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (!inst || inst->pending)
14862306a36Sopenharmony_ci		return;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	list_for_each_entry_safe(cmd, tmp, &inst->cmd_q, list) {
15162306a36Sopenharmony_ci		list_del_init(&cmd->list);
15262306a36Sopenharmony_ci		if (vpu_session_process_cmd(inst, cmd))
15362306a36Sopenharmony_ci			dev_err(inst->dev, "[%d] process cmd %s fail\n",
15462306a36Sopenharmony_ci				inst->id, vpu_id_name(cmd->id));
15562306a36Sopenharmony_ci		if (cmd->request) {
15662306a36Sopenharmony_ci			inst->pending = (void *)cmd;
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci		vpu_free_cmd(cmd);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int vpu_request_cmd(struct vpu_inst *inst, u32 id, void *data,
16462306a36Sopenharmony_ci			   unsigned long *key, int *sync)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct vpu_core *core;
16762306a36Sopenharmony_ci	struct vpu_cmd_t *cmd;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (!inst || !inst->core)
17062306a36Sopenharmony_ci		return -EINVAL;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	core = inst->core;
17362306a36Sopenharmony_ci	cmd = vpu_alloc_cmd(inst, id, data);
17462306a36Sopenharmony_ci	if (!cmd)
17562306a36Sopenharmony_ci		return -ENOMEM;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	mutex_lock(&core->cmd_lock);
17862306a36Sopenharmony_ci	cmd->key = ++inst->cmd_seq;
17962306a36Sopenharmony_ci	cmd->last_response_cmd = &inst->last_response_cmd;
18062306a36Sopenharmony_ci	if (key)
18162306a36Sopenharmony_ci		*key = cmd->key;
18262306a36Sopenharmony_ci	if (sync)
18362306a36Sopenharmony_ci		*sync = cmd->request ? true : false;
18462306a36Sopenharmony_ci	list_add_tail(&cmd->list, &inst->cmd_q);
18562306a36Sopenharmony_ci	vpu_process_cmd_request(inst);
18662306a36Sopenharmony_ci	mutex_unlock(&core->cmd_lock);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return 0;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void vpu_clear_pending(struct vpu_inst *inst)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	if (!inst || !inst->pending)
19462306a36Sopenharmony_ci		return;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	vpu_free_cmd(inst->pending);
19762306a36Sopenharmony_ci	wake_up_all(&inst->core->ack_wq);
19862306a36Sopenharmony_ci	inst->pending = NULL;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic bool vpu_check_response(struct vpu_cmd_t *cmd, u32 response, u32 handled)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct vpu_cmd_request *request;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (!cmd || !cmd->request)
20662306a36Sopenharmony_ci		return false;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	request = cmd->request;
20962306a36Sopenharmony_ci	if (request->response != response)
21062306a36Sopenharmony_ci		return false;
21162306a36Sopenharmony_ci	if (request->handled != handled)
21262306a36Sopenharmony_ci		return false;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return true;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ciint vpu_response_cmd(struct vpu_inst *inst, u32 response, u32 handled)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct vpu_core *core;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (!inst || !inst->core)
22262306a36Sopenharmony_ci		return -EINVAL;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	core = inst->core;
22562306a36Sopenharmony_ci	mutex_lock(&core->cmd_lock);
22662306a36Sopenharmony_ci	if (vpu_check_response(inst->pending, response, handled))
22762306a36Sopenharmony_ci		vpu_clear_pending(inst);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	vpu_process_cmd_request(inst);
23062306a36Sopenharmony_ci	mutex_unlock(&core->cmd_lock);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_civoid vpu_clear_request(struct vpu_inst *inst)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct vpu_cmd_t *cmd;
23862306a36Sopenharmony_ci	struct vpu_cmd_t *tmp;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	mutex_lock(&inst->core->cmd_lock);
24162306a36Sopenharmony_ci	if (inst->pending)
24262306a36Sopenharmony_ci		vpu_clear_pending(inst);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	list_for_each_entry_safe(cmd, tmp, &inst->cmd_q, list) {
24562306a36Sopenharmony_ci		list_del_init(&cmd->list);
24662306a36Sopenharmony_ci		vpu_free_cmd(cmd);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	mutex_unlock(&inst->core->cmd_lock);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic bool check_is_responsed(struct vpu_inst *inst, unsigned long key)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	unsigned long last_response = atomic_long_read(&inst->last_response_cmd);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (key <= last_response && (last_response - key) < (ULONG_MAX >> 1))
25662306a36Sopenharmony_ci		return true;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return false;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int sync_session_response(struct vpu_inst *inst, unsigned long key, long timeout, int try)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct vpu_core *core;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!inst || !inst->core)
26662306a36Sopenharmony_ci		return -EINVAL;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	core = inst->core;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	call_void_vop(inst, wait_prepare);
27162306a36Sopenharmony_ci	wait_event_timeout(core->ack_wq, check_is_responsed(inst, key), timeout);
27262306a36Sopenharmony_ci	call_void_vop(inst, wait_finish);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (!check_is_responsed(inst, key)) {
27562306a36Sopenharmony_ci		if (try)
27662306a36Sopenharmony_ci			return -EINVAL;
27762306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] sync session timeout\n", inst->id);
27862306a36Sopenharmony_ci		set_bit(inst->id, &core->hang_mask);
27962306a36Sopenharmony_ci		mutex_lock(&inst->core->cmd_lock);
28062306a36Sopenharmony_ci		vpu_clear_pending(inst);
28162306a36Sopenharmony_ci		mutex_unlock(&inst->core->cmd_lock);
28262306a36Sopenharmony_ci		return -EINVAL;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void vpu_core_keep_active(struct vpu_core *core)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct vpu_rpc_event pkt;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	memset(&pkt, 0, sizeof(pkt));
29362306a36Sopenharmony_ci	vpu_iface_pack_cmd(core, &pkt, 0, VPU_CMD_ID_NOOP, NULL);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	dev_dbg(core->dev, "try to wake up\n");
29662306a36Sopenharmony_ci	mutex_lock(&core->cmd_lock);
29762306a36Sopenharmony_ci	if (vpu_cmd_send(core, &pkt))
29862306a36Sopenharmony_ci		dev_err(core->dev, "fail to keep active\n");
29962306a36Sopenharmony_ci	mutex_unlock(&core->cmd_lock);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int vpu_session_send_cmd(struct vpu_inst *inst, u32 id, void *data)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	unsigned long key;
30562306a36Sopenharmony_ci	int sync = false;
30662306a36Sopenharmony_ci	int ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (inst->id < 0)
30962306a36Sopenharmony_ci		return -EINVAL;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ret = vpu_request_cmd(inst, id, data, &key, &sync);
31262306a36Sopenharmony_ci	if (ret)
31362306a36Sopenharmony_ci		goto exit;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* workaround for a firmware issue,
31662306a36Sopenharmony_ci	 * firmware should be waked up by start or configure command,
31762306a36Sopenharmony_ci	 * but there is a very small change that firmware failed to wakeup.
31862306a36Sopenharmony_ci	 * in such case, try to wakeup firmware again by sending a noop command
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	if (sync && (id == VPU_CMD_ID_CONFIGURE_CODEC || id == VPU_CMD_ID_START)) {
32162306a36Sopenharmony_ci		if (sync_session_response(inst, key, VPU_TIMEOUT_WAKEUP, 1))
32262306a36Sopenharmony_ci			vpu_core_keep_active(inst->core);
32362306a36Sopenharmony_ci		else
32462306a36Sopenharmony_ci			goto exit;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (sync)
32862306a36Sopenharmony_ci		ret = sync_session_response(inst, key, VPU_TIMEOUT, 0);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciexit:
33162306a36Sopenharmony_ci	if (ret)
33262306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] send cmd %s fail\n", inst->id, vpu_id_name(id));
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return ret;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ciint vpu_session_configure_codec(struct vpu_inst *inst)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_CONFIGURE_CODEC, NULL);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ciint vpu_session_start(struct vpu_inst *inst)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	vpu_trace(inst->dev, "[%d]\n", inst->id);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_START, NULL);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciint vpu_session_stop(struct vpu_inst *inst)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	int ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	vpu_trace(inst->dev, "[%d]\n", inst->id);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	ret = vpu_session_send_cmd(inst, VPU_CMD_ID_STOP, NULL);
35662306a36Sopenharmony_ci	/* workaround for a firmware bug,
35762306a36Sopenharmony_ci	 * if the next command is too close after stop cmd,
35862306a36Sopenharmony_ci	 * the firmware may enter wfi wrongly.
35962306a36Sopenharmony_ci	 */
36062306a36Sopenharmony_ci	usleep_range(3000, 5000);
36162306a36Sopenharmony_ci	return ret;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ciint vpu_session_encode_frame(struct vpu_inst *inst, s64 timestamp)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_FRAME_ENCODE, &timestamp);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciint vpu_session_alloc_fs(struct vpu_inst *inst, struct vpu_fs_info *fs)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_FS_ALLOC, fs);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ciint vpu_session_release_fs(struct vpu_inst *inst, struct vpu_fs_info *fs)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_FS_RELEASE, fs);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ciint vpu_session_abort(struct vpu_inst *inst)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_ABORT, NULL);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ciint vpu_session_rst_buf(struct vpu_inst *inst)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_RST_BUF, NULL);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint vpu_session_fill_timestamp(struct vpu_inst *inst, struct vpu_ts_info *info)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_TIMESTAMP, info);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciint vpu_session_update_parameters(struct vpu_inst *inst, void *arg)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	if (inst->type & VPU_CORE_TYPE_DEC)
39762306a36Sopenharmony_ci		vpu_iface_set_decode_params(inst, arg, 1);
39862306a36Sopenharmony_ci	else
39962306a36Sopenharmony_ci		vpu_iface_set_encode_params(inst, arg, 1);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_UPDATE_PARAMETER, arg);
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ciint vpu_session_debug(struct vpu_inst *inst)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	return vpu_session_send_cmd(inst, VPU_CMD_ID_DEBUG, NULL);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ciint vpu_core_snapshot(struct vpu_core *core)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct vpu_inst *inst;
41262306a36Sopenharmony_ci	int ret;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!core || list_empty(&core->instances))
41562306a36Sopenharmony_ci		return 0;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	inst = list_first_entry(&core->instances, struct vpu_inst, list);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	reinit_completion(&core->cmp);
42062306a36Sopenharmony_ci	ret = vpu_session_send_cmd(inst, VPU_CMD_ID_SNAPSHOT, NULL);
42162306a36Sopenharmony_ci	if (ret)
42262306a36Sopenharmony_ci		return ret;
42362306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&core->cmp, VPU_TIMEOUT);
42462306a36Sopenharmony_ci	if (!ret) {
42562306a36Sopenharmony_ci		dev_err(core->dev, "snapshot timeout\n");
42662306a36Sopenharmony_ci		return -EINVAL;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint vpu_core_sw_reset(struct vpu_core *core)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct vpu_rpc_event pkt;
43562306a36Sopenharmony_ci	int ret;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	memset(&pkt, 0, sizeof(pkt));
43862306a36Sopenharmony_ci	vpu_iface_pack_cmd(core, &pkt, 0, VPU_CMD_ID_FIRM_RESET, NULL);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	reinit_completion(&core->cmp);
44162306a36Sopenharmony_ci	mutex_lock(&core->cmd_lock);
44262306a36Sopenharmony_ci	ret = vpu_cmd_send(core, &pkt);
44362306a36Sopenharmony_ci	mutex_unlock(&core->cmd_lock);
44462306a36Sopenharmony_ci	if (ret)
44562306a36Sopenharmony_ci		return ret;
44662306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&core->cmp, VPU_TIMEOUT);
44762306a36Sopenharmony_ci	if (!ret) {
44862306a36Sopenharmony_ci		dev_err(core->dev, "sw reset timeout\n");
44962306a36Sopenharmony_ci		return -EINVAL;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
454