msm: vidc_3x: Add new video driver to support CMA buffers

- current driver does not support if input and output buffers allocated
  in CMA region with stage1 translation bypassed.
  To accept such kind of buffers by video firmware, all context banks has
  to be detached and attached with new CMA address ranges.
- Also video firmware needs be unload and load to protect nonsecure and
  secure accordingly.
- Added new video driver node which indicates video session buffers
  comes from CMA region, it helps video firmware configure at beginning of
  session creation.

Change-Id: I7e797ffc2e84b4018ece3886edc94571cc35b6e2
Signed-off-by: Srinu Gorle <sgorle@codeaurora.org>
This commit is contained in:
Srinu Gorle 2020-04-11 21:57:45 +05:30
parent 5397d43a06
commit 5fba8031c3
8 changed files with 242 additions and 15 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-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
@ -430,7 +430,12 @@ static int alloc_dma_mem(size_t size, u32 align, u32 flags,
}
ion_flags |= ION_FLAG_SECURE | secure_flag;
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
if (res->cma_status) {
heap_mask = ION_HEAP(ION_VIDEO_HEAP_ID);
ion_flags |= ION_FLAG_CP_CAMERA_ENCODE;
} else {
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
}
if (res->slave_side_cp) {
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-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
@ -586,6 +586,32 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
"Failed to create link name sysfs for encoder");
goto err_enc_attr_link_name;
}
/* setup the encoder device with cma */
core->vdev[MSM_VIDC_ENCODER_CMA].vdev.release =
msm_vidc_release_video_device;
core->vdev[MSM_VIDC_ENCODER_CMA].vdev.fops = &msm_v4l2_vidc_fops;
core->vdev[MSM_VIDC_ENCODER_CMA].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
core->vdev[MSM_VIDC_ENCODER_CMA].vdev.vfl_dir = VFL_DIR_M2M;
core->vdev[MSM_VIDC_ENCODER_CMA].type = MSM_VIDC_ENCODER_CMA;
core->vdev[MSM_VIDC_ENCODER_CMA].vdev.v4l2_dev = &core->v4l2_dev;
rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER_CMA].vdev,
VFL_TYPE_GRABBER, nr + 3);
if (rc) {
dprintk(VIDC_ERR,
"Failed to register video cma encoder device");
goto err_enc_register;
}
video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER_CMA].vdev, core);
dev = &core->vdev[MSM_VIDC_ENCODER_CMA].vdev.dev;
rc = device_create_file(dev, &dev_attr_link_name);
if (rc) {
dprintk(VIDC_ERR,
"Failed to create link name sysfs for encoder cma");
goto err_enc_attr_link_name;
}
/* finish setting up the 'core' */
mutex_lock(&vidc_driver->lock);

View File

@ -22,6 +22,7 @@
#include <linux/delay.h>
#include "vidc_hfi_api.h"
#include "msm_vidc_dcvs.h"
#include "msm_vidc_res_parse.h"
#define MAX_EVENTS 30
@ -1242,6 +1243,9 @@ void *msm_vidc_open(int core_id, int session_type)
struct msm_vidc_core *core = NULL;
int rc = 0;
int i = 0;
bool reconfig_core = false;
bool is_cma_enabled = false;
struct hfi_device *hdev = NULL;
if (core_id >= MSM_VIDC_CORES_MAX ||
session_type >= MSM_VIDC_MAX_DEVICES) {
@ -1256,6 +1260,13 @@ void *msm_vidc_open(int core_id, int session_type)
goto err_invalid_core;
}
if ((session_type == MSM_VIDC_ENCODER_CMA) &&
!core->resources.cma_exist) {
dprintk(VIDC_ERR, "Failed cma not enabled\n");
goto err_invalid_core;
}
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst) {
dprintk(VIDC_ERR, "Failed to allocate memory\n");
@ -1280,6 +1291,18 @@ void *msm_vidc_open(int core_id, int session_type)
kref_init(&inst->kref);
is_cma_enabled = core->resources.cma_status;
reconfig_core =
((!is_cma_enabled && session_type == MSM_VIDC_ENCODER_CMA) ||
(is_cma_enabled && session_type != MSM_VIDC_ENCODER_CMA)) ?
true : false;
dprintk(VIDC_DBG, "reconfig_core %d , cma_status %d , session_type %d ",
reconfig_core, core->resources.cma_status, session_type);
if (session_type == MSM_VIDC_ENCODER_CMA)
session_type = MSM_VIDC_ENCODER;
inst->session_type = session_type;
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
@ -1322,6 +1345,50 @@ void *msm_vidc_open(int core_id, int session_type)
setup_event_queue(inst, &core->vdev[session_type].vdev);
if (reconfig_core) {
mutex_lock(&core->lock);
if (!list_empty(&core->instances)) {
dprintk(VIDC_ERR,
"failed due to pending instances in core");
mutex_unlock(&core->lock);
goto fail_toggle_cma;
}
mutex_unlock(&core->lock);
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
if (rc) {
dprintk(VIDC_ERR,
"MSM_VIDC_CORE_UNINIT failed\n");
}
cancel_delayed_work(&core->fw_unload_work);
mutex_lock(&core->lock);
hdev = core->device;
rc = call_hfi_op(hdev, core_release,
hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR,
"Failed to release core, id = %d\n",
core->id);
mutex_unlock(&core->lock);
goto fail_toggle_cma;
}
core->state = VIDC_CORE_UNINIT;
kfree(core->capabilities);
core->capabilities = NULL;
msm_vidc_enable_cma(&core->resources, !is_cma_enabled);
if (rc) {
dprintk(VIDC_ERR,
"%s CMA failed\n", is_cma_enabled ?
"enable":"disable");
mutex_unlock(&core->lock);
goto fail_toggle_cma;
}
core->resources.cma_status = !is_cma_enabled;
mutex_unlock(&core->lock);
}
mutex_lock(&core->lock);
list_add_tail(&inst->list, &core->instances);
mutex_unlock(&core->lock);
@ -1343,11 +1410,15 @@ void *msm_vidc_open(int core_id, int session_type)
msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
return inst;
fail_init:
mutex_lock(&core->lock);
list_del(&inst->list);
mutex_unlock(&core->lock);
fail_toggle_cma:
mutex_lock(&core->lock);
v4l2_fh_del(&inst->event_handler);
v4l2_fh_exit(&inst->event_handler);
list_del(&inst->list);
mutex_unlock(&core->lock);
vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);

View File

@ -20,9 +20,14 @@
#include "msm_vidc_resources.h"
#include "msm_vidc_res_parse.h"
#include "venus_boot.h"
#include <soc/qcom/scm.h>
#include "soc/qcom/secure_buffer.h"
#include <asm/cacheflush.h>
#include <linux/io.h>
#define VENUS_DEVICE_ID 0x0
#define SECURE_SYSCALL_ID 0x18
enum clock_properties {
CLOCK_PROP_HAS_SCALING = 1 << 0,
};
@ -1265,12 +1270,63 @@ static int get_secure_vmid(struct context_bank_info *cb)
return VMID_INVAL;
}
static int msm_vidc_switch_vmid(int vmid, struct context_bank_info *cb)
{
struct scm_desc desc = {0};
uint32_t *sid_info = NULL;
int rc = 0;
if (!cb) {
dprintk(VIDC_ERR, "%s: invalid context bank device\n",
__func__);
return -EIO;
}
sid_info = kzalloc(sizeof(uint32_t) * cb->num_sids, GFP_KERNEL);
if (!sid_info) {
dprintk(VIDC_ERR, "%s: memory allocation failred\n",
__func__);
return -ENOMEM;
}
memcpy(sid_info, &cb->sids, sizeof(uint32_t) * cb->num_sids);
desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
desc.args[0] = VENUS_DEVICE_ID;
desc.args[1] = SCM_BUFFER_PHYS(sid_info);
desc.args[2] = sizeof(uint32_t) * cb->num_sids;
desc.args[3] = vmid;
dmac_flush_range(sid_info, sid_info + 1);
if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID), &desc)) {
dprintk(VIDC_ERR, "call to hypervisor failed\n");
rc = -EINVAL;
}
dprintk(VIDC_DBG, "%s switched to 0x%x vmid\n", cb->name, vmid);
kfree(sid_info);
return rc;
}
static void msm_vidc_detach_context_banks(
struct msm_vidc_platform_resources *res)
{
struct context_bank_info *cb = NULL;
list_for_each_entry(cb, &res->context_banks, list) {
arm_iommu_detach_device(cb->dev);
if (cb->mapping)
arm_iommu_release_mapping(cb->mapping);
}
}
static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
struct device *dev)
struct device *dev, int cma_enable)
{
int rc = 0;
int secure_vmid = VMID_INVAL;
struct bus_type *bus;
u32 start_addr = 0, pool_size = 0;
int s1_bypass = 1;
if (!dev || !cb) {
dprintk(VIDC_ERR,
@ -1286,8 +1342,15 @@ static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
goto remove_cb;
}
cb->mapping = arm_iommu_create_mapping(bus, cb->addr_range.start,
cb->addr_range.size);
if (cma_enable) {
start_addr = cb->cma.addr_range.start;
pool_size = cb->cma.addr_range.size;
} else {
start_addr = cb->addr_range.start;
pool_size = cb->addr_range.size;
}
cb->mapping = arm_iommu_create_mapping(bus, start_addr, pool_size);
if (IS_ERR_OR_NULL(cb->mapping)) {
dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__);
rc = PTR_ERR(cb->mapping) ?: -ENODEV;
@ -1296,12 +1359,26 @@ static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
if (cb->is_secure) {
secure_vmid = get_secure_vmid(cb);
if (cma_enable && cb->cma.s1_bypass)
secure_vmid = VMID_CP_CAMERA_ENCODE;
rc = iommu_domain_set_attr(cb->mapping->domain,
DOMAIN_ATTR_SECURE_VMID, &secure_vmid);
if (rc) {
dprintk(VIDC_ERR,
"%s - programming secure vmid failed: %s %d\n",
__func__, dev_name(dev), rc);
"%s - programming secure vmid failed: %s 0x%x\n",
__func__, dev_name(dev), rc);
goto release_mapping;
}
}
if (cma_enable && cb->cma.s1_bypass) {
s1_bypass = cb->cma.s1_bypass;
rc = iommu_domain_set_attr(cb->mapping->domain,
DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
if (rc) {
dprintk(VIDC_ERR,
"%s S1 bypass failed rc %d ", __func__, rc);
goto release_mapping;
}
}
@ -1324,11 +1401,12 @@ static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(dev));
dprintk(VIDC_DBG, "Attached %s and created mapping cma status %d\n",
dev_name(dev), cma_enable);
dprintk(VIDC_DBG,
"Context bank name:%s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, mapping: %pK",
cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
cb->addr_range.size, cb->dev, cb->mapping);
cb->name, cb->buffer_type, cb->is_secure, start_addr,
pool_size, cb->dev, cb->mapping);
return rc;
@ -1497,7 +1575,7 @@ static int msm_vidc_populate_context_bank(struct device *dev,
cb->cma.addr_range.start, cb->cma.addr_range.size,
cb->cma.s1_bypass, cb->buffer_type);
rc = msm_vidc_setup_context_bank(cb, dev);
rc = msm_vidc_setup_context_bank(cb, dev, false);
if (rc) {
dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
goto err_setup_cb;
@ -1594,7 +1672,7 @@ static int msm_vidc_populate_legacy_context_bank(
goto err_setup_cb;
}
rc = msm_vidc_setup_context_bank(cb, cb->dev);
rc = msm_vidc_setup_context_bank(cb, cb->dev, false);
if (rc) {
dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
goto err_setup_cb;
@ -1681,3 +1759,42 @@ int read_bus_resources_from_dt(struct platform_device *pdev)
return msm_vidc_populate_bus(&pdev->dev, &core->resources);
}
int msm_vidc_enable_cma(struct msm_vidc_platform_resources *res, bool enable)
{
int rc;
int secure_vmid = VMID_INVAL;
struct context_bank_info *cb = NULL;
dprintk(VIDC_DBG, "%s: In enable status %d\n", __func__, enable);
msm_vidc_detach_context_banks(res);
list_for_each_entry(cb, &res->context_banks, list) {
if (cb->is_secure && cb->cma.s1_bypass) {
if (enable) {
rc = msm_vidc_switch_vmid(VMID_CP_CAMERA_ENCODE,
cb);
if (rc) {
dprintk(VIDC_ERR,
"failed SID switching\n");
goto detach_cb;
}
} else {
secure_vmid = get_secure_vmid(cb);
rc = msm_vidc_switch_vmid(secure_vmid, cb);
if (rc)
goto detach_cb;
}
}
rc = msm_vidc_setup_context_bank(cb, cb->dev, enable);
if (rc)
goto detach_cb;
}
return rc;
detach_cb:
dprintk(VIDC_DBG, "%s: - failed %d\n", __func__, enable);
msm_vidc_detach_context_banks(res);
return rc;
}

View File

@ -31,4 +31,5 @@ int msm_vidc_load_u32_table(struct platform_device *pdev,
struct device_node *of_node, char *table_name, int struct_size,
u32 **table, u32 *num_elements);
int msm_vidc_enable_cma(struct msm_vidc_platform_resources *res, bool enable);
#endif

View File

@ -200,6 +200,7 @@ struct msm_vidc_platform_resources {
uint32_t max_inst_count;
uint32_t max_secure_inst_count;
bool cma_exist;
bool cma_status;
};
static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)

View File

@ -4020,6 +4020,7 @@ static int __protect_cp_mem(struct venus_hfi_device *device)
int rc = 0;
struct context_bank_info *cb;
struct scm_desc desc = {0};
bool is_cma_enabled = false;
if (!device)
return -EINVAL;
@ -4029,9 +4030,11 @@ static int __protect_cp_mem(struct venus_hfi_device *device)
memprot.cp_nonpixel_start = 0x0;
memprot.cp_nonpixel_size = 0x0;
is_cma_enabled = device->res->cma_status;
list_for_each_entry(cb, &device->res->context_banks, list) {
if (!strcmp(cb->name, "venus_ns")) {
desc.args[1] = memprot.cp_size =
is_cma_enabled ? cb->cma.addr_range.start :
cb->addr_range.start;
dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n",
__func__, memprot.cp_size);
@ -4039,8 +4042,10 @@ static int __protect_cp_mem(struct venus_hfi_device *device)
if (!strcmp(cb->name, "venus_sec_non_pixel")) {
desc.args[2] = memprot.cp_nonpixel_start =
is_cma_enabled ? cb->cma.addr_range.start :
cb->addr_range.start;
desc.args[3] = memprot.cp_nonpixel_size =
is_cma_enabled ? cb->cma.addr_range.size :
cb->addr_range.size;
dprintk(VIDC_DBG,
"%s memprot.cp_nonpixel_start: %#x size: %#x\n",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-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
@ -93,6 +93,7 @@ enum core_id {
enum session_type {
MSM_VIDC_ENCODER = 0,
MSM_VIDC_DECODER,
MSM_VIDC_ENCODER_CMA,
MSM_VIDC_UNKNOWN,
MSM_VIDC_MAX_DEVICES = MSM_VIDC_UNKNOWN,
};