Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d58ce43a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: cvp: Add snapshot of fastcvpd driver"

parents 854ae4bd f7ee4da4
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -541,6 +541,15 @@ source "drivers/s390/char/Kconfig"
source "drivers/char/xillybus/Kconfig"
source "drivers/char/diag/Kconfig"

config MSM_FASTCVPD
	bool "QTI FASTCVP driver"
	depends on QCOM_GLINK
	help
	  This driver exposes APIs (Application Program Interface) to video driver
	  to share HFI command queue address to CDSP (Compute Digital Signal
	  Processor) and handle errors to exit gracefully in case video and cdsp
	  subsystems crash.

config MSM_ADSPRPC
        tristate "QTI ADSP RPC driver"
        depends on QCOM_GLINK
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o
ifdef CONFIG_COMPAT
  obj-$(CONFIG_MSM_ADSPRPC)	+= adsprpc_compat.o
endif
obj-$(CONFIG_MSM_FASTCVPD)	+= fastcvpd.o
obj-$(CONFIG_ADI)		+= adi.o
obj-$(CONFIG_DIAG_CHAR)		+= diag/
obj-$(CONFIG_OKL4_PIPE)		+= okl4_pipe.o
+341 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include <linux/module.h>
#include <linux/rpmsg.h>
#include <linux/of_platform.h>
#include <soc/qcom/secure_buffer.h>
#include "linux/fastcvpd.h"

#define VMID_CDSP_Q6 (30)
#define SRC_VM_NUM 1
#define DEST_VM_NUM 2
#define FASTCVPD_VIDEO_SEND_HFI_CMD_QUEUE 0
#define FASTCVPD_VIDEO_SUSPEND 1
#define FASTCVPD_VIDEO_RESUME 2
#define FASTCVPD_VIDEO_SHUTDOWN 3
#define STATUS_INIT 0
#define STATUS_DEINIT 1
#define STATUS_OK 2
#define STATUS_SSR 3

struct fastcvpd_cmd_msg {
	uint32_t cmd_msg_type;
	int ret_val;
	uint64_t msg_ptr;
	uint32_t msg_ptr_len;
};

struct fastcvpd_cmd_msg_rsp {
	int ret_val;
};

struct fastcvpd_apps {
	struct rpmsg_device *chan;
	struct mutex smd_mutex;
	int rpmsg_register;
	uint32_t cdsp_state;
	uint32_t video_shutdown;
};

static struct completion work;

static struct fastcvpd_apps gfa_cv;

static struct fastcvpd_cmd_msg cmd_msg;

static struct fastcvpd_cmd_msg_rsp cmd_msg_rsp;

static int fastcvpd_send_cmd(void *msg, uint32_t len)
{
	struct fastcvpd_apps *me = &gfa_cv;
	int err;

	if (IS_ERR_OR_NULL(me->chan)) {
		err = -EINVAL;
		goto bail;
	}
	err = rpmsg_send(me->chan->ept, msg, len);

bail:
	return err;
}

static int fastcvpd_rpmsg_probe(struct rpmsg_device *rpdev)
{
	int err = 0;
	struct fastcvpd_apps *me = &gfa_cv;
	uint32_t cdsp_state, video_shutdown;
	uint64_t msg_ptr;
	uint32_t msg_ptr_len;
	int srcVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
	int destVM[SRC_VM_NUM] = {VMID_HLOS};
	int destVMperm[SRC_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC };

	if (strcmp(rpdev->dev.parent->of_node->name, "cdsp")) {
		pr_err("%s: Failed to probe rpmsg device.Node name:%s\n",
			__func__, rpdev->dev.parent->of_node->name);
		err = -EINVAL;
		goto bail;
	}
	mutex_lock(&me->smd_mutex);
	me->chan = rpdev;
	cdsp_state = me->cdsp_state;
	video_shutdown = me->video_shutdown;
	msg_ptr = cmd_msg.msg_ptr;
	msg_ptr_len =  cmd_msg.msg_ptr_len;
	mutex_unlock(&me->smd_mutex);

	if (cdsp_state == STATUS_SSR && video_shutdown == STATUS_OK) {
		err = hyp_assign_phys((uint64_t)msg_ptr,
			msg_ptr_len, srcVM, DEST_VM_NUM, destVM,
			destVMperm, SRC_VM_NUM);
		if (err) {
			pr_err("%s: Failed to hyp_assign. err=%d\n",
				__func__, err);
			return err;
		}
		err = fastcvpd_video_send_cmd_hfi_queue(
			(phys_addr_t *)msg_ptr, msg_ptr_len);
		if (err) {
			pr_err("%s: Failed to send HFI Queue address. err=%d\n",
			__func__, err);
			goto bail;
		}
		mutex_lock(&me->smd_mutex);
		cdsp_state = me->cdsp_state;
		mutex_unlock(&me->smd_mutex);
	}

	pr_info("%s: Successfully probed. cdsp_state=%d video_shutdown=%d\n",
		__func__, cdsp_state, video_shutdown);
bail:
	return err;
}

static void fastcvpd_rpmsg_remove(struct rpmsg_device *rpdev)
{
	struct fastcvpd_apps *me = &gfa_cv;

	mutex_lock(&me->smd_mutex);
	me->chan = NULL;
	me->cdsp_state = STATUS_SSR;
	mutex_unlock(&me->smd_mutex);
	pr_info("%s: CDSP SSR triggered\n", __func__);
}

static int fastcvpd_rpmsg_callback(struct rpmsg_device *rpdev,
	void *data, int len, void *priv, u32 addr)
{
	int *rpmsg_resp = (int *)data;

	cmd_msg_rsp.ret_val = *rpmsg_resp;
	complete(&work);

	return 0;
}

int fastcvpd_video_send_cmd_hfi_queue(phys_addr_t *phys_addr,
	uint32_t size_in_bytes)
{
	int err;
	struct fastcvpd_cmd_msg local_cmd_msg;
	struct fastcvpd_apps *me = &gfa_cv;
	int srcVM[SRC_VM_NUM] = {VMID_HLOS};
	int destVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
	int destVMperm[DEST_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC,
		PERM_READ | PERM_WRITE | PERM_EXEC };

	local_cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SEND_HFI_CMD_QUEUE;
	local_cmd_msg.msg_ptr = (uint64_t)phys_addr;
	local_cmd_msg.msg_ptr_len = size_in_bytes;
	mutex_lock(&me->smd_mutex);
	cmd_msg.msg_ptr = (uint64_t)phys_addr;
	cmd_msg.msg_ptr_len = (size_in_bytes);
	mutex_unlock(&me->smd_mutex);

	pr_debug("%s :: address of buffer, PA=0x%pK  size_buff=%d\n",
		__func__, phys_addr, size_in_bytes);

	err = hyp_assign_phys((uint64_t)local_cmd_msg.msg_ptr,
		local_cmd_msg.msg_ptr_len, srcVM, SRC_VM_NUM, destVM,
		destVMperm, DEST_VM_NUM);
	if (err) {
		pr_err("%s: Failed in hyp_assign. err=%d\n",
			__func__, err);
		return err;
	}

	err = fastcvpd_send_cmd
			 (&local_cmd_msg, sizeof(struct fastcvpd_cmd_msg));
	if (err != 0)
		pr_err("%s: fastcvpd_send_cmd failed with err=%d\n",
			__func__, err);
	else {
		mutex_lock(&me->smd_mutex);
		me->video_shutdown = STATUS_OK;
		me->cdsp_state = STATUS_OK;
		mutex_unlock(&me->smd_mutex);
	}

	return err;
}
EXPORT_SYMBOL(fastcvpd_video_send_cmd_hfi_queue);

int fastcvpd_video_suspend(uint32_t session_flag)
{
	int err = 0;
	struct fastcvpd_cmd_msg local_cmd_msg;
	struct fastcvpd_apps *me = &gfa_cv;
	uint32_t cdsp_state;

	mutex_lock(&me->smd_mutex);
	cdsp_state = me->cdsp_state;
	mutex_unlock(&me->smd_mutex);

	if (cdsp_state == STATUS_SSR)
		return 0;

	local_cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SUSPEND;
	err = fastcvpd_send_cmd
			 (&local_cmd_msg, sizeof(struct fastcvpd_cmd_msg));
	if (err != 0)
		pr_err("%s: fastcvpd_send_cmd failed with err=%d\n",
			__func__, err);

	return err;
}
EXPORT_SYMBOL(fastcvpd_video_suspend);

int fastcvpd_video_resume(uint32_t session_flag)
{
	int err;
	struct fastcvpd_cmd_msg local_cmd_msg;
	struct fastcvpd_apps *me = &gfa_cv;
	uint32_t cdsp_state;

	mutex_lock(&me->smd_mutex);
	cdsp_state = me->cdsp_state;
	mutex_unlock(&me->smd_mutex);

	if (cdsp_state == STATUS_SSR)
		return 0;

	local_cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_RESUME;
	err = fastcvpd_send_cmd
			 (&local_cmd_msg, sizeof(struct fastcvpd_cmd_msg));
	if (err != 0)
		pr_err("%s: fastcvpd_send_cmd failed with err=%d\n",
			__func__, err);

	return err;
}
EXPORT_SYMBOL(fastcvpd_video_resume);

int fastcvpd_video_shutdown(uint32_t session_flag)
{
	struct fastcvpd_apps *me = &gfa_cv;
	int err, local_cmd_msg_rsp;
	struct fastcvpd_cmd_msg local_cmd_msg;
	int srcVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
	int destVM[SRC_VM_NUM] = {VMID_HLOS};
	int destVMperm[SRC_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC };

	local_cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SHUTDOWN;
	err = fastcvpd_send_cmd
			 (&local_cmd_msg, sizeof(struct fastcvpd_cmd_msg));
	if (err != 0)
		pr_err("%s: fastcvpd_send_cmd failed with err=%d\n",
			__func__, err);

	wait_for_completion(&work);

	mutex_lock(&me->smd_mutex);
	me->video_shutdown = STATUS_SSR;
	local_cmd_msg.msg_ptr = cmd_msg.msg_ptr;
	local_cmd_msg.msg_ptr_len = cmd_msg.msg_ptr_len;
	mutex_unlock(&me->smd_mutex);
	local_cmd_msg_rsp = cmd_msg_rsp.ret_val;
	if (local_cmd_msg_rsp == 0) {
		err = hyp_assign_phys((uint64_t)local_cmd_msg.msg_ptr,
			local_cmd_msg.msg_ptr_len, srcVM, DEST_VM_NUM, destVM,
			destVMperm, SRC_VM_NUM);
		if (err) {
			pr_err("%s: Failed to hyp_assign. err=%d\n",
				__func__, err);
			return err;
		}
	} else {
		pr_err("%s: Skipping hyp_assign as CDSP sent invalid response=%d\n",
			__func__, local_cmd_msg_rsp);
	}

	return err;
}
EXPORT_SYMBOL(fastcvpd_video_shutdown);

static const struct rpmsg_device_id fastcvpd_rpmsg_match[] = {
	{ FASTCVPD_GLINK_GUID },
	{ },
};

static struct rpmsg_driver fastcvpd_rpmsg_client = {
	.id_table = fastcvpd_rpmsg_match,
	.probe = fastcvpd_rpmsg_probe,
	.remove = fastcvpd_rpmsg_remove,
	.callback = fastcvpd_rpmsg_callback,
	.drv = {
		.name = "qcom,msm_fastcvpd_rpmsg",
	},
};

static int __init fastcvpd_device_init(void)
{
	struct fastcvpd_apps *me = &gfa_cv;
	int err;

	init_completion(&work);
	mutex_init(&me->smd_mutex);
	me->video_shutdown = STATUS_INIT;
	me->cdsp_state = STATUS_INIT;
	err = register_rpmsg_driver(&fastcvpd_rpmsg_client);
	if (err) {
		pr_err("%s : register_rpmsg_driver failed with err %d\n",
			__func__, err);
		goto register_bail;
	}
	me->rpmsg_register = 1;
	return 0;

register_bail:
	me->video_shutdown = STATUS_DEINIT;
	me->cdsp_state = STATUS_DEINIT;
	return err;
}

static void __exit fastcvpd_device_exit(void)
{
	struct fastcvpd_apps *me = &gfa_cv;

	me->video_shutdown = STATUS_DEINIT;
	me->cdsp_state = STATUS_DEINIT;
	mutex_destroy(&me->smd_mutex);
	if (me->rpmsg_register == 1)
		unregister_rpmsg_driver(&fastcvpd_rpmsg_client);
}

late_initcall(fastcvpd_device_init);
module_exit(fastcvpd_device_exit);

MODULE_LICENSE("GPL v2");