diff --git a/drivers/media/platform/msm/vidc_3x/msm_smem.c b/drivers/media/platform/msm/vidc_3x/msm_smem.c index 522e57254b42..ddbfc987f107 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_smem.c +++ b/drivers/media/platform/msm/vidc_3x/msm_smem.c @@ -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); diff --git a/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c index 20d5d29f9088..bf0ad561a42a 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c @@ -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); diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c index a16f25a6c99e..6c8a7a1f2f03 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c @@ -22,6 +22,7 @@ #include #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); diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c index c79adf233c27..0fcee0f18dc8 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c @@ -20,9 +20,14 @@ #include "msm_vidc_resources.h" #include "msm_vidc_res_parse.h" #include "venus_boot.h" +#include #include "soc/qcom/secure_buffer.h" +#include #include +#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; +} diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h index dbd640d7dd96..7c1c02f281af 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h @@ -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 diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h index d6dff556e541..3741f61c8bee 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h @@ -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) diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c index cf5ee5078982..58f87a86d5b5 100644 --- a/drivers/media/platform/msm/vidc_3x/venus_hfi.c +++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c @@ -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", diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h index fe8a25f45c43..643d6b4e0d7e 100644 --- a/include/media/msm_vidc.h +++ b/include/media/msm_vidc.h @@ -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, };