diff options
Diffstat (limited to 'drivers/media/platform/qcom')
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-vfe.c | 23 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss.c | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/core.c | 32 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/core.h | 6 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/firmware.c | 235 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/firmware.h | 17 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_cmds.c | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_venus.c | 15 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_venus_io.h | 8 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/vdec.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/venc.c | 23 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/venc_ctrls.c | 36 |
13 files changed, 348 insertions, 56 deletions
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index ed6a557de65d..a8c542fa647d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -37,9 +37,9 @@ /* VFE halt timeout */ #define VFE_HALT_TIMEOUT_MS 100 /* Max number of frame drop updates per frame */ -#define VFE_FRAME_DROP_UPDATES 5 -/* Frame drop value. NOTE: VAL + UPDATES should not exceed 31 */ -#define VFE_FRAME_DROP_VAL 20 +#define VFE_FRAME_DROP_UPDATES 2 +/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */ +#define VFE_FRAME_DROP_VAL 30 #define VFE_NEXT_SOF_MS 500 @@ -659,7 +659,9 @@ static int vfe_enable_output(struct vfe_line *line) struct vfe_device *vfe = to_vfe(line); struct vfe_output *output = &line->output; const struct vfe_hw_ops *ops = vfe->ops; + struct media_entity *sensor; unsigned long flags; + unsigned int frame_skip = 0; unsigned int i; u16 ub_size; @@ -667,6 +669,17 @@ static int vfe_enable_output(struct vfe_line *line) if (!ub_size) return -EINVAL; + sensor = camss_find_sensor(&line->subdev.entity); + if (sensor) { + struct v4l2_subdev *subdev = + media_entity_to_v4l2_subdev(sensor); + + v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip); + /* Max frame skip is 29 frames */ + if (frame_skip > VFE_FRAME_DROP_VAL - 1) + frame_skip = VFE_FRAME_DROP_VAL - 1; + } + spin_lock_irqsave(&vfe->output_lock, flags); ops->reg_update_clear(vfe, line->id); @@ -695,10 +708,10 @@ static int vfe_enable_output(struct vfe_line *line) switch (output->state) { case VFE_OUTPUT_SINGLE: - vfe_output_frame_drop(vfe, output, 1); + vfe_output_frame_drop(vfe, output, 1 << frame_skip); break; case VFE_OUTPUT_CONTINUOUS: - vfe_output_frame_drop(vfe, output, 3); + vfe_output_frame_drop(vfe, output, 3 << frame_skip); break; default: vfe_output_frame_drop(vfe, output, 0); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 45978db3b0be..63da18773d24 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -346,7 +346,7 @@ void camss_disable_clocks(int nclocks, struct camss_clock *clock) * * Return a pointer to sensor media entity or NULL if not found */ -static struct media_entity *camss_find_sensor(struct media_entity *entity) +struct media_entity *camss_find_sensor(struct media_entity *entity) { struct media_pad *pad; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 57b269ca93fd..1376b07889bf 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -106,6 +106,7 @@ void camss_add_clock_margin(u64 *rate); int camss_enable_clocks(int nclocks, struct camss_clock *clock, struct device *dev); void camss_disable_clocks(int nclocks, struct camss_clock *clock); +struct media_entity *camss_find_sensor(struct media_entity *entity); int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock); int camss_pm_domain_on(struct camss *camss, int id); void camss_pm_domain_off(struct camss *camss, int id); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index bb6add9d340e..cb411eb85ee4 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -76,7 +76,7 @@ static void venus_sys_error_handler(struct work_struct *work) hfi_core_deinit(core, true); hfi_destroy(core); mutex_lock(&core->lock); - venus_shutdown(core->dev); + venus_shutdown(core); pm_runtime_put_sync(core->dev); @@ -84,7 +84,7 @@ static void venus_sys_error_handler(struct work_struct *work) pm_runtime_get_sync(core->dev); - ret |= venus_boot(core->dev, core->res->fwname); + ret |= venus_boot(core); ret |= hfi_core_resume(core, true); @@ -264,6 +264,14 @@ static int venus_probe(struct platform_device *pdev) if (ret) return ret; + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + INIT_LIST_HEAD(&core->instances); mutex_init(&core->lock); INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); @@ -284,7 +292,15 @@ static int venus_probe(struct platform_device *pdev) if (ret < 0) goto err_runtime_disable; - ret = venus_boot(dev, core->res->fwname); + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) + goto err_runtime_disable; + + ret = venus_firmware_init(core); + if (ret) + goto err_runtime_disable; + + ret = venus_boot(core); if (ret) goto err_runtime_disable; @@ -308,10 +324,6 @@ static int venus_probe(struct platform_device *pdev) if (ret) goto err_core_deinit; - ret = of_platform_populate(dev->of_node, NULL, NULL, dev); - if (ret) - goto err_dev_unregister; - ret = pm_runtime_put_sync(dev); if (ret) goto err_dev_unregister; @@ -323,7 +335,7 @@ err_dev_unregister: err_core_deinit: hfi_core_deinit(core, false); err_venus_shutdown: - venus_shutdown(dev); + venus_shutdown(core); err_runtime_disable: pm_runtime_set_suspended(dev); pm_runtime_disable(dev); @@ -344,9 +356,11 @@ static int venus_remove(struct platform_device *pdev) WARN_ON(ret); hfi_destroy(core); - venus_shutdown(dev); + venus_shutdown(core); of_platform_depopulate(dev); + venus_firmware_deinit(core); + pm_runtime_put_sync(dev); pm_runtime_disable(dev); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 2f02365f4818..6382cea29185 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -98,6 +98,7 @@ struct venus_caps { * @dev: convenience struct device pointer * @dev_dec: convenience struct device pointer for decoder device * @dev_enc: convenience struct device pointer for encoder device + * @use_tz: a flag that suggests presence of trustzone * @lock: a lock for this strucure * @instances: a list_head of all instances * @insts_count: num of instances @@ -129,6 +130,11 @@ struct venus_core { struct device *dev; struct device *dev_dec; struct device *dev_enc; + unsigned int use_tz; + struct video_firmware { + struct device *dev; + struct iommu_domain *iommu_domain; + } fw; struct mutex lock; struct list_head instances; atomic_t insts_count; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index c4a577848dd7..c29acfd70c1b 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -15,32 +15,66 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/kernel.h> +#include <linux/iommu.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> #include <linux/qcom_scm.h> #include <linux/sizes.h> #include <linux/soc/qcom/mdt_loader.h> +#include "core.h" #include "firmware.h" +#include "hfi_venus_io.h" #define VENUS_PAS_ID 9 #define VENUS_FW_MEM_SIZE (6 * SZ_1M) +#define VENUS_FW_START_ADDR 0x0 -int venus_boot(struct device *dev, const char *fwname) +static void venus_reset_cpu(struct venus_core *core) +{ + void __iomem *base = core->base; + + writel(0, base + WRAPPER_FW_START_ADDR); + writel(VENUS_FW_MEM_SIZE, base + WRAPPER_FW_END_ADDR); + writel(0, base + WRAPPER_CPA_START_ADDR); + writel(VENUS_FW_MEM_SIZE, base + WRAPPER_CPA_END_ADDR); + writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_START_ADDR); + writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_END_ADDR); + writel(0x0, base + WRAPPER_CPU_CGC_DIS); + writel(0x0, base + WRAPPER_CPU_CLOCK_CONFIG); + + /* Bring ARM9 out of reset */ + writel(0, base + WRAPPER_A9SS_SW_RESET); +} + +int venus_set_hw_state(struct venus_core *core, bool resume) +{ + if (core->use_tz) + return qcom_scm_set_remote_state(resume, 0); + + if (resume) + venus_reset_cpu(core); + else + writel(1, core->base + WRAPPER_A9SS_SW_RESET); + + return 0; +} + +static int venus_load_fw(struct venus_core *core, const char *fwname, + phys_addr_t *mem_phys, size_t *mem_size) { const struct firmware *mdt; struct device_node *node; - phys_addr_t mem_phys; + struct device *dev; struct resource r; ssize_t fw_size; - size_t mem_size; void *mem_va; int ret; - if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available()) - return -EPROBE_DEFER; - + dev = core->dev; node = of_parse_phandle(dev->of_node, "memory-region", 0); if (!node) { dev_err(dev, "no memory-region specified\n"); @@ -51,16 +85,16 @@ int venus_boot(struct device *dev, const char *fwname) if (ret) return ret; - mem_phys = r.start; - mem_size = resource_size(&r); + *mem_phys = r.start; + *mem_size = resource_size(&r); - if (mem_size < VENUS_FW_MEM_SIZE) + if (*mem_size < VENUS_FW_MEM_SIZE) return -EINVAL; - mem_va = memremap(r.start, mem_size, MEMREMAP_WC); + mem_va = memremap(r.start, *mem_size, MEMREMAP_WC); if (!mem_va) { dev_err(dev, "unable to map memory region: %pa+%zx\n", - &r.start, mem_size); + &r.start, *mem_size); return -ENOMEM; } @@ -75,24 +109,181 @@ int venus_boot(struct device *dev, const char *fwname) goto err_unmap; } - ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, - mem_size, NULL); + if (core->use_tz) + ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, + mem_va, *mem_phys, *mem_size, NULL); + else + ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID, + mem_va, *mem_phys, *mem_size, NULL); release_firmware(mdt); - if (ret) - goto err_unmap; - - ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); - if (ret) - goto err_unmap; - err_unmap: memunmap(mem_va); return ret; } -int venus_shutdown(struct device *dev) +static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys, + size_t mem_size) +{ + struct iommu_domain *iommu; + struct device *dev; + int ret; + + dev = core->fw.dev; + if (!dev) + return -EPROBE_DEFER; + + iommu = core->fw.iommu_domain; + + ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV); + if (ret) { + dev_err(dev, "could not map video firmware region\n"); + return ret; + } + + venus_reset_cpu(core); + + return 0; +} + +static int venus_shutdown_no_tz(struct venus_core *core) +{ + struct iommu_domain *iommu; + size_t unmapped; + u32 reg; + struct device *dev = core->fw.dev; + void __iomem *base = core->base; + + /* Assert the reset to ARM9 */ + reg = readl_relaxed(base + WRAPPER_A9SS_SW_RESET); + reg |= WRAPPER_A9SS_SW_RESET_BIT; + writel_relaxed(reg, base + WRAPPER_A9SS_SW_RESET); + + /* Make sure reset is asserted before the mapping is removed */ + mb(); + + iommu = core->fw.iommu_domain; + + unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, VENUS_FW_MEM_SIZE); + if (unmapped != VENUS_FW_MEM_SIZE) + dev_err(dev, "failed to unmap firmware\n"); + + return 0; +} + +int venus_boot(struct venus_core *core) { - return qcom_scm_pas_shutdown(VENUS_PAS_ID); + struct device *dev = core->dev; + phys_addr_t mem_phys; + size_t mem_size; + int ret; + + if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || + (core->use_tz && !qcom_scm_is_available())) + return -EPROBE_DEFER; + + ret = venus_load_fw(core, core->res->fwname, &mem_phys, &mem_size); + if (ret) { + dev_err(dev, "fail to load video firmware\n"); + return -EINVAL; + } + + if (core->use_tz) + ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); + else + ret = venus_boot_no_tz(core, mem_phys, mem_size); + + return ret; +} + +int venus_shutdown(struct venus_core *core) +{ + int ret; + + if (core->use_tz) + ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); + else + ret = venus_shutdown_no_tz(core); + + return ret; +} + +int venus_firmware_init(struct venus_core *core) +{ + struct platform_device_info info; + struct iommu_domain *iommu_dom; + struct platform_device *pdev; + struct device_node *np; + int ret; + + np = of_get_child_by_name(core->dev->of_node, "video-firmware"); + if (!np) { + core->use_tz = true; + return 0; + } + + memset(&info, 0, sizeof(info)); + info.fwnode = &np->fwnode; + info.parent = core->dev; + info.name = np->name; + info.dma_mask = DMA_BIT_MASK(32); + + pdev = platform_device_register_full(&info); + if (IS_ERR(pdev)) { + of_node_put(np); + return PTR_ERR(pdev); + } + + pdev->dev.of_node = np; + + ret = of_dma_configure(&pdev->dev, np, true); + if (ret) { + dev_err(core->dev, "dma configure fail\n"); + goto err_unregister; + } + + core->fw.dev = &pdev->dev; + + iommu_dom = iommu_domain_alloc(&platform_bus_type); + if (!iommu_dom) { + dev_err(core->fw.dev, "Failed to allocate iommu domain\n"); + ret = -ENOMEM; + goto err_unregister; + } + + ret = iommu_attach_device(iommu_dom, core->fw.dev); + if (ret) { + dev_err(core->fw.dev, "could not attach device\n"); + goto err_iommu_free; + } + + core->fw.iommu_domain = iommu_dom; + + of_node_put(np); + + return 0; + +err_iommu_free: + iommu_domain_free(iommu_dom); +err_unregister: + platform_device_unregister(pdev); + of_node_put(np); + return ret; +} + +void venus_firmware_deinit(struct venus_core *core) +{ + struct iommu_domain *iommu; + + if (!core->fw.dev) + return; + + iommu = core->fw.iommu_domain; + + iommu_detach_device(iommu, core->fw.dev); + iommu_domain_free(iommu); + + platform_device_unregister(to_platform_device(core->fw.dev)); } diff --git a/drivers/media/platform/qcom/venus/firmware.h b/drivers/media/platform/qcom/venus/firmware.h index 428efb56d339..119a9a4fc1a2 100644 --- a/drivers/media/platform/qcom/venus/firmware.h +++ b/drivers/media/platform/qcom/venus/firmware.h @@ -16,7 +16,20 @@ struct device; -int venus_boot(struct device *dev, const char *fwname); -int venus_shutdown(struct device *dev); +int venus_firmware_init(struct venus_core *core); +void venus_firmware_deinit(struct venus_core *core); +int venus_boot(struct venus_core *core); +int venus_shutdown(struct venus_core *core); +int venus_set_hw_state(struct venus_core *core, bool suspend); + +static inline int venus_set_hw_state_suspend(struct venus_core *core) +{ + return venus_set_hw_state(core, false); +} + +static inline int venus_set_hw_state_resume(struct venus_core *core) +{ + return venus_set_hw_state(core, true); +} #endif diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index e8389d8d8c48..87a441488e15 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1215,7 +1215,7 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, } case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: /* not implemented on Venus 4xx */ - break; + return -ENOTSUPP; default: return pkt_session_set_property_3xx(pkt, cookie, ptype, pdata); } diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 124085556b94..5c1e5b4f767a 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/kernel.h> -#include <linux/qcom_scm.h> #include <linux/slab.h> #include "core.h" @@ -27,6 +26,7 @@ #include "hfi_msgs.h" #include "hfi_venus.h" #include "hfi_venus_io.h" +#include "firmware.h" #define HFI_MASK_QHDR_TX_TYPE 0xff000000 #define HFI_MASK_QHDR_RX_TYPE 0x00ff0000 @@ -55,11 +55,6 @@ #define IFACEQ_VAR_LARGE_PKT_SIZE 512 #define IFACEQ_VAR_HUGE_PKT_SIZE (1024 * 12) -enum tzbsp_video_state { - TZBSP_VIDEO_STATE_SUSPEND = 0, - TZBSP_VIDEO_STATE_RESUME -}; - struct hfi_queue_table_header { u32 version; u32 size; @@ -575,7 +570,7 @@ static int venus_power_off(struct venus_hfi_device *hdev) if (!hdev->power_enabled) return 0; - ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0); + ret = venus_set_hw_state_suspend(hdev->core); if (ret) return ret; @@ -595,7 +590,7 @@ static int venus_power_on(struct venus_hfi_device *hdev) if (hdev->power_enabled) return 0; - ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0); + ret = venus_set_hw_state_resume(hdev->core); if (ret) goto err; @@ -608,7 +603,7 @@ static int venus_power_on(struct venus_hfi_device *hdev) return 0; err_suspend: - qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0); + venus_set_hw_state_suspend(hdev->core); err: hdev->power_enabled = false; return ret; @@ -1355,6 +1350,8 @@ static int venus_session_set_property(struct venus_inst *inst, u32 ptype, pkt = (struct hfi_session_set_property_pkt *)packet; ret = pkt_session_set_property(pkt, inst, ptype, pdata); + if (ret == -ENOTSUPP) + return 0; if (ret) return ret; diff --git a/drivers/media/platform/qcom/venus/hfi_venus_io.h b/drivers/media/platform/qcom/venus/hfi_venus_io.h index def0926a6dee..ef0c72a0c892 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus_io.h +++ b/drivers/media/platform/qcom/venus/hfi_venus_io.h @@ -112,6 +112,14 @@ #define WRAPPER_CPU_STATUS (WRAPPER_BASE + 0x2014) #define WRAPPER_CPU_STATUS_WFI BIT(0) #define WRAPPER_SW_RESET (WRAPPER_BASE + 0x3000) +#define WRAPPER_CPA_START_ADDR (WRAPPER_BASE + 0x1020) +#define WRAPPER_CPA_END_ADDR (WRAPPER_BASE + 0x1024) +#define WRAPPER_FW_START_ADDR (WRAPPER_BASE + 0x1028) +#define WRAPPER_FW_END_ADDR (WRAPPER_BASE + 0x102C) +#define WRAPPER_NONPIX_START_ADDR (WRAPPER_BASE + 0x1030) +#define WRAPPER_NONPIX_END_ADDR (WRAPPER_BASE + 0x1034) +#define WRAPPER_A9SS_SW_RESET (WRAPPER_BASE + 0x3000) +#define WRAPPER_A9SS_SW_RESET_BIT BIT(4) /* Venus 4xx */ #define WRAPPER_VCODEC0_MMCC_POWER_STATUS (WRAPPER_BASE + 0x90) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 189ec975c6bb..282de21cf2e1 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -885,10 +885,8 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vbuf->field = V4L2_FIELD_NONE; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - unsigned int opb_sz = venus_helper_get_opb_size(inst); - vb = &vbuf->vb2_buf; - vb2_set_plane_payload(vb, 0, bytesused ? : opb_sz); + vb2_set_plane_payload(vb, 0, bytesused); vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index ce85962b6adc..32cff294582f 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -651,6 +651,8 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_framerate frate; struct hfi_bitrate brate; struct hfi_idr_period idrp; + struct hfi_quantization quant; + struct hfi_quantization_range quant_range; u32 ptype, rate_control, bitrate, profile = 0, level = 0; int ret; @@ -770,6 +772,23 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; + ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP; + quant.qp_i = ctr->h264_i_qp; + quant.qp_p = ctr->h264_p_qp; + quant.qp_b = ctr->h264_b_qp; + quant.layer_id = 0; + ret = hfi_session_set_property(inst, ptype, &quant); + if (ret) + return ret; + + ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; + quant_range.min_qp = ctr->h264_min_qp; + quant_range.max_qp = ctr->h264_max_qp; + quant_range.layer_id = 0; + ret = hfi_session_set_property(inst, ptype, &quant_range); + if (ret) + return ret; + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) { profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE, ctr->profile.h264); @@ -1074,7 +1093,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->ops = &venc_vb2_ops; src_vq->mem_ops = &vb2_dma_sg_memops; @@ -1090,7 +1109,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->ops = &venc_vb2_ops; dst_vq->mem_ops = &vb2_dma_sg_memops; diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 459101728d26..ac1e1d26f341 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -79,7 +79,10 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct venus_inst *inst = ctrl_to_inst(ctrl); struct venc_controls *ctr = &inst->controls.enc; + struct hfi_enable en = { .enable = 1 }; + struct hfi_bitrate brate; u32 bframes; + u32 ptype; int ret; switch (ctrl->id) { @@ -88,6 +91,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE: ctr->bitrate = ctrl->val; + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + brate.bitrate = ctr->bitrate; + brate.layer_id = 0; + + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) { + mutex_unlock(&inst->lock); + return ret; + } + } + mutex_unlock(&inst->lock); break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: ctr->bitrate_peak = ctrl->val; @@ -173,6 +189,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->num_b_frames = bframes; break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + ptype = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME; + ret = hfi_session_set_property(inst, ptype, &en); + + if (ret) { + mutex_unlock(&inst->lock); + return ret; + } + } + mutex_unlock(&inst->lock); + break; default: return -EINVAL; } @@ -188,7 +217,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 27); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28); if (ret) return ret; @@ -295,7 +324,7 @@ int venc_ctrl_init(struct venus_inst *inst) 0, INTRA_REFRESH_MBS_MAX, 1, 0); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 12); + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, 1, 128, 1, 1); @@ -309,6 +338,9 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0, (1 << 16) - 1, 1, 0); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0); + ret = inst->ctrl_handler.error; if (ret) goto err; |