You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
8.6 KiB
344 lines
8.6 KiB
/*
|
|
* Copyright (c) 2018, 2020 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 };
|
|
unsigned long ret;
|
|
|
|
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);
|
|
|
|
ret = wait_for_completion_timeout(&work, msecs_to_jiffies(1000));
|
|
if (!ret) {
|
|
pr_err("%s: wait timeout", __func__);
|
|
return -EBUSY;
|
|
}
|
|
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");
|
|
|