aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dechesne <nicolas.dechesne@linaro.org>2015-06-18 10:26:00 +0200
committerNicolas Dechesne <nicolas.dechesne@linaro.org>2015-06-18 10:26:09 +0200
commit39c45dd18669b0b8ace5b5a37b68e64cc3408de6 (patch)
treee0a5440fd16ff2b7cad9160bea41ad58107dee41
parent4531bab9e1aa272905c5361f9219d35d14514eb4 (diff)
parent866fdf69f5ddae91907a2a88b59d0a816daeddb1 (diff)
Merge branch 'db410c_gpu2-venus' into release/qcomlt-4.0ubuntu-qcom-dragonboard410c-15.06
Signed-off-by: Nicolas Dechesne <nicolas.dechesne@linaro.org> Conflicts: arch/arm64/boot/dts/qcom/msm8916.dtsi
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi135
-rw-r--r--arch/arm64/configs/defconfig3
-rw-r--r--arch/arm64/mm/dma-mapping.c67
-rw-r--r--drivers/clk/qcom/gcc-msm8916.c5
-rw-r--r--drivers/firmware/qcom_scm-32.c48
-rw-r--r--drivers/firmware/qcom_scm-64.c44
-rw-r--r--drivers/firmware/qcom_scm.c15
-rw-r--r--drivers/firmware/qcom_scm.h5
-rw-r--r--drivers/iommu/qcom/msm_iommu-v1.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/msm/Kconfig7
-rw-r--r--drivers/media/platform/msm/Makefile6
-rw-r--r--drivers/media/platform/msm/vidc/Kconfig11
-rw-r--r--drivers/media/platform/msm/vidc/Makefile17
-rw-r--r--drivers/media/platform/msm/vidc/hfi_packetization.c2048
-rw-r--r--drivers/media/platform/msm/vidc/hfi_packetization.h99
-rw-r--r--drivers/media/platform/msm/vidc/hfi_response_handler.c1475
-rw-r--r--drivers/media/platform/msm/vidc/msm_smem.c794
-rw-r--r--drivers/media/platform/msm/vidc/msm_v4l2_vidc.c816
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c2779
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.h39
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c3771
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.h40
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c1521
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c4328
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.h86
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_dcvs.c617
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_dcvs.h50
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c403
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.h176
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_internal.h382
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c963
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.h28
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_resources.h147
-rw-r--r--drivers/media/platform/msm/vidc/q6_hfi.c1230
-rw-r--r--drivers/media/platform/msm/vidc/q6_hfi.h133
-rw-r--r--drivers/media/platform/msm/vidc/venus_boot.c520
-rw-r--r--drivers/media/platform/msm/vidc/venus_boot.h22
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c4331
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.h280
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi.c82
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi.h890
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_api.h1392
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_helper.h1075
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_io.h191
-rw-r--r--drivers/media/platform/msm/vidc/vmem/Kconfig3
-rw-r--r--drivers/media/platform/msm/vidc/vmem/Makefile2
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem.c716
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem.h35
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem_debugfs.c82
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem_debugfs.h21
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c8
-rw-r--r--include/linux/qcom_scm.h4
-rw-r--r--include/media/msm_media_info.h611
-rw-r--r--include/media/msm_vidc.h134
-rw-r--r--include/media/videobuf2-core.h4
-rw-r--r--include/soc/qcom/ocmem.h266
-rw-r--r--include/trace/events/msm_vidc.h315
-rw-r--r--include/uapi/Kbuild1
-rw-r--r--include/uapi/linux/v4l2-controls.h4
-rw-r--r--include/uapi/linux/videodev2.h9
-rw-r--r--include/uapi/media/Kbuild2
-rw-r--r--include/uapi/media/msm-v4l2-controls.h455
-rw-r--r--include/uapi/media/msm_vidc.h154
68 files changed, 33892 insertions, 21 deletions
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 60fe83b703d4..d92f605d3c54 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -59,19 +59,12 @@
reg = <0x0 0x8b600000 0x0 0x0600000>;
};
- secure_mem: secure_region {
- compatible = "shared-dma-pool";
- reusable;
- alignment = <0 0x400000>;
- size = <0 0x7000000>;
- };
-
venus_qseecom_mem: venus_qseecom_region {
compatible = "shared-dma-pool";
alloc-ranges = <0 0x80000000 0 0x10000000>;
reusable;
alignment = <0 0x400000>;
- size = <0 0x1400000>;
+ size = <0 0x800000>;
};
audio_mem: audio_region {
@@ -1613,6 +1606,132 @@
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>;
};
+
+ qcom,iommu-domains {
+ compatible = "qcom,iommu-domains";
+
+ /*
+ * non-secure addr pool from 1500 MB to 3548 MB
+ */
+ venus_domain_ns: qcom,iommu-domain1 {
+ label = "venus_ns";
+ qcom,iommu-contexts = <&venus_ns>;
+ qcom,virtual-addr-pool = <0x5dc00000 0x8f000000>;
+ };
+
+ /*
+ * secure bitstream addr pool from 1200 MB to 1500 MB
+ */
+ venus_domain_sec_bitstream: qcom,iommu-domain2 {
+ label = "venus_sec_bitstream";
+ qcom,iommu-contexts = <&venus_sec_bitstream>;
+ qcom,virtual-addr-pool = <0x4b000000 0x12c00000>;
+ qcom,secure-domain;
+ };
+
+ /*
+ * secure pixel addr pool from 616 MB to 1200 MB
+ */
+ venus_domain_sec_pixel: qcom,iommu-domain3 {
+ label = "venus_sec_pixel";
+ qcom,iommu-contexts = <&venus_sec_pixel>;
+ qcom,virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-domain;
+ };
+
+ /*
+ * secure non-pixel addr pool from 16 MB to 616 MB
+ */
+ venus_domain_sec_non_pixel: qcom,iommu-domain4 {
+ label = "venus_sec_non_pixel";
+ qcom,iommu-contexts = <&venus_sec_non_pixel>;
+ qcom,virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-domain;
+ };
+ };
+
+ qcom,vidc@1d00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0x01d00000 0xff000>;
+ interrupts = <0 44 0>;
+ power-domains = <&gcc VENUS_GDSC>;
+ clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>,
+ <&gcc GCC_VENUS0_AHB_CLK>,
+ <&gcc GCC_VENUS0_AXI_CLK>;
+ clock-names = "core_clk", "iface_clk", "bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0>;
+ qcom,load-freq-tbl = <352800 228570000 0xffffffff>,
+ <352800 228570000 0x55555555>,
+ <244800 160000000 0xffffffff>,
+ <244800 160000000 0x55555555>,
+ <108000 100000000 0xffffffff>,
+ <108000 100000000 0x55555555>;
+ qcom,hfi = "venus";
+ qcom,reg-presets = <0xE0020 0x05555556>,
+ <0xE0024 0x05555556>,
+ <0x80124 0x00000003>;
+ qcom,qdss-presets = <0x826000 0x1000>,
+ <0x827000 0x1000>,
+ <0x822000 0x1000>,
+ <0x803000 0x1000>,
+ <0x9180000 0x1000>,
+ <0x9181000 0x1000>;
+ qcom,max-hw-load = <352800>; /* 720p @ 30 + 1080p @ 30 */
+ qcom,enable-idle-indicator;
+ qcom,msm-bus-clients {
+ qcom,msm-bus-client@0 {
+ qcom,msm-bus,name = "venc-ddr";
+ qcom,msm-bus,num-cases = <6>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 133600 674400>, /* VGA 30 fps */
+ <63 512 400900 1079000>, /* VGA 60 fps */
+ <63 512 400900 1079000>, /* 720p 30 fps */
+ <63 512 908600 1537600>, /* 720p 60 fps */
+ <63 512 908600 1537600>; /* 1080p 30 fps */
+ qcom,bus-configs = <0x01000414>;
+ };
+
+ qcom,msm-bus-client@1 {
+ qcom,msm-bus,name = "vdec-ddr";
+ qcom,msm-bus,num-cases = <6>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 99600 831900>, /* VGA 30 fps */
+ <63 512 298900 831900>, /* VGA 60 fps */
+ <63 512 298900 831900>, /* 720p 30 fps */
+ <63 512 677600 1331000>, /* 720p 60 fps */
+ <63 512 677600 1331000>; /* 1080p 30 fps */
+ qcom,bus-configs = <0x030fcfff>;
+ };
+ };
+
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,vidc-domain-phandle = <&venus_domain_ns>;
+ qcom,vidc-partition-buffer-types = <0xfff>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
+ qcom,vidc-partition-buffer-types = <0x241>;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
+ qcom,vidc-partition-buffer-types = <0x106>;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
+ qcom,vidc-partition-buffer-types = <0x480>;
+ };
+ };
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 08c009487ad4..aa2d497eab51 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -139,6 +139,9 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_QCOM_RPM=y
CONFIG_REGULATOR_QCOM_SPMI=y
CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MSM_VIDC_V4L2=y
CONFIG_DRM=y
CONFIG_DRM_I2C_ADV7511=y
# CONFIG_DRM_I2C_ADV7511_SLAVE_ENCODER is not set
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 9f080ae0f6fa..842c354ac19f 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1005,6 +1005,39 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
}
+static int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+ struct scatterlist *sg, unsigned int len, int opt)
+{
+ s32 ret = 0;
+ u32 offset = 0;
+ u32 start_iova = iova;
+
+ BUG_ON(iova & (~PAGE_MASK));
+
+ while (offset < len) {
+ phys_addr_t phys = page_to_phys(sg_page(sg));
+ u32 page_len = PAGE_ALIGN(sg->offset + sg->length);
+
+ ret = iommu_map(domain, iova, phys, page_len, opt);
+ if (ret)
+ goto fail;
+
+ iova += page_len;
+ offset += page_len;
+ if (offset < len)
+ sg = sg_next(sg);
+ }
+
+ goto out;
+
+fail:
+ /* undo mappings already done in case of error */
+ iommu_unmap(domain, start_iova, offset);
+out:
+
+ return ret;
+}
+
/**
* arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
* @dev: valid struct device pointer
@@ -1020,7 +1053,29 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
{
- return __iommu_map_sg(dev, sg, nents, dir, attrs, false);
+ struct scatterlist *s;
+ int ret, i;
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int iova, total_length = 0, current_offset = 0;
+ int prot = __dma_direction_to_prot(dir);
+
+ for_each_sg(sg, s, nents, i)
+ total_length += s->length;
+
+ iova = __alloc_iova(mapping, total_length);
+ ret = iommu_map_range(mapping->domain, iova, sg, total_length, prot);
+ if (ret) {
+ __free_iova(mapping, iova, total_length);
+ return 0;
+ }
+
+ for_each_sg(sg, s, nents, i) {
+ s->dma_address = iova + current_offset;
+ s->dma_length = total_length - current_offset;
+ current_offset += s->length;
+ }
+
+ return nents;
}
static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
@@ -1070,7 +1125,15 @@ void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- __iommu_unmap_sg(dev, sg, nents, dir, attrs, false);
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int total_length = sg_dma_len(sg);
+ unsigned int iova = sg_dma_address(sg);
+
+ total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length);
+ iova &= PAGE_MASK;
+
+ iommu_unmap(mapping->domain, iova, total_length);
+ __free_iova(mapping, iova, total_length);
}
/**
diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c
index 605ec730c97b..dc1768a4f568 100644
--- a/drivers/clk/qcom/gcc-msm8916.c
+++ b/drivers/clk/qcom/gcc-msm8916.c
@@ -3015,6 +3015,7 @@ static struct gdsc venus_gdsc = {
.pd = {
.name = "venus",
},
+ .con_ids = { NULL },
};
static struct gdsc mdss_gdsc = {
@@ -3022,6 +3023,7 @@ static struct gdsc mdss_gdsc = {
.pd = {
.name = "mdss",
},
+ .con_ids = { NULL },
};
static struct gdsc jpeg_gdsc = {
@@ -3029,6 +3031,7 @@ static struct gdsc jpeg_gdsc = {
.pd = {
.name = "jpeg",
},
+ .con_ids = { NULL },
};
static struct gdsc vfe_gdsc = {
@@ -3036,6 +3039,7 @@ static struct gdsc vfe_gdsc = {
.pd = {
.name = "vfe",
},
+ .con_ids = { NULL },
};
static struct gdsc oxili_gdsc = {
@@ -3044,6 +3048,7 @@ static struct gdsc oxili_gdsc = {
.name = "oxili",
},
.root_con_id = "gfx3d_clk_src",
+ .con_ids = { NULL },
};
static struct clk_regmap *gcc_msm8916_clocks[] = {
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 3361082b57c9..750db6a545c6 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -742,3 +742,51 @@ int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
return 0;
}
+
+#define TZBSP_VIDEO_SET_STATE 0xa
+int __qcom_scm_set_video_state(u32 state, u32 spare)
+{
+ struct {
+ u32 state;
+ u32 spare;
+ } req;
+ int scm_ret = 0;
+ int ret;
+
+ req.state = state;
+ req.spare = spare;
+
+ ret = qcom_scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &req,
+ sizeof(req), &scm_ret, sizeof(scm_ret));
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
+
+#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
+
+int __qcom_scm_mem_protect_video_var(u32 start, u32 size, u32 nonpixel_start,
+ u32 nonpixel_size)
+{
+ struct {
+ u32 cp_start;
+ u32 cp_size;
+ u32 cp_nonpixel_start;
+ u32 cp_nonpixel_size;
+ } req;
+ int ret, scm_ret;
+
+ req.cp_start = start;
+ req.cp_size = size;
+ req.cp_nonpixel_start = nonpixel_start;
+ req.cp_nonpixel_size = nonpixel_size;
+
+ ret = qcom_scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &req,
+ sizeof(req), &scm_ret, sizeof(scm_ret));
+
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index e13326f6fd9b..7ee5cecb2032 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -688,6 +688,50 @@ int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
return 0;
}
+#define TZBSP_VIDEO_SET_STATE 0xa
+int __qcom_scm_set_video_state(u32 state, u32 spare)
+{
+ struct qcom_scm_desc desc = {0};
+ int ret, scm_ret;
+
+ desc.args[0] = state;
+ desc.args[1] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &desc);
+
+ scm_ret = desc.ret[0];
+
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
+
+#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
+
+int __qcom_scm_mem_protect_video_var(u32 start, u32 size, u32 nonpixel_start,
+ u32 nonpixel_size)
+{
+ struct qcom_scm_desc desc = {0};
+ int ret, scm_ret;
+
+ desc.args[0] = start;
+ desc.args[1] = size;
+ desc.args[2] = nonpixel_start;
+ desc.args[3] = nonpixel_size;
+ desc.arginfo = QCOM_SCM_ARGS(4);
+
+ ret = qcom_scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &desc);
+
+ scm_ret = desc.ret[0];
+
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
+
#define QCOM_SCM_SVC_INFO 0x6
static int __init qcom_scm_init(void)
{
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 59625416a2e2..c5cac7f18aaa 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -145,3 +145,18 @@ int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
return __qcom_scm_restore_sec_cfg(device_id, spare);
}
EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
+
+int qcom_scm_set_video_state(u32 state, u32 spare)
+{
+ return __qcom_scm_set_video_state(state, spare);
+}
+EXPORT_SYMBOL(qcom_scm_set_video_state);
+
+int qcom_scm_mem_protect_video_var(u32 start, u32 size,
+ u32 nonpixel_start,
+ u32 nonpixel_size)
+{
+ return __qcom_scm_mem_protect_video_var(start, size, nonpixel_start,
+ nonpixel_size);
+}
+EXPORT_SYMBOL(qcom_scm_mem_protect_video_var);
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index dbc74cc9cca6..927e00c5084a 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -34,6 +34,7 @@ enum scm_cmd {
PAS_SHUTDOWN_CMD,
};
+#define SCM_SVC_BOOT 0x1
#define SCM_SVC_PIL 0x2
#define SCM_SVC_INFO 0x6
@@ -59,4 +60,8 @@ extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
extern int __qcom_scm_get_feat_version(u32 feat);
extern int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+extern int __qcom_scm_set_video_state(u32 state, u32 spare);
+extern int __qcom_scm_mem_protect_video_var(u32 start, u32 size,
+ u32 nonpixel_start,
+ u32 nonpixel_size);
#endif
diff --git a/drivers/iommu/qcom/msm_iommu-v1.c b/drivers/iommu/qcom/msm_iommu-v1.c
index e3676229a9eb..43092d7e9778 100644
--- a/drivers/iommu/qcom/msm_iommu-v1.c
+++ b/drivers/iommu/qcom/msm_iommu-v1.c
@@ -996,7 +996,7 @@ static size_t msm_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
}
for_each_sg(sg, tmp, nents, i)
- len += sg->length;
+ len += tmp->length;
ret = msm_iommu_pagetable_map_range(&priv->pt, iova, sg, len, prot);
if (ret)
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 2709b83d57b1..da48ad7745f7 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -212,8 +212,8 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
/* sanitycheck insmod options */
if (tsbufs < 2)
tsbufs = 2;
- if (tsbufs > VIDEO_MAX_FRAME)
- tsbufs = VIDEO_MAX_FRAME;
+ if (tsbufs > VB2_MAX_FRAME)
+ tsbufs = VB2_MAX_FRAME;
if (ts_nr_packets < 4)
ts_nr_packets = 4;
if (ts_nr_packets > 312)
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index 5306e549e526..2a3397792be9 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -189,8 +189,8 @@ int saa7134_vbi_init1(struct saa7134_dev *dev)
if (vbibufs < 2)
vbibufs = 2;
- if (vbibufs > VIDEO_MAX_FRAME)
- vbibufs = VIDEO_MAX_FRAME;
+ if (vbibufs > VB2_MAX_FRAME)
+ vbibufs = VB2_MAX_FRAME;
return 0;
}
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 99d09a7566d3..c08c8558bcb4 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -2011,7 +2011,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
int ret;
/* sanitycheck insmod options */
- if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+ if (gbuffers < 2 || gbuffers > VB2_MAX_FRAME)
gbuffers = 2;
if (gbufsize > gbufsize_max)
gbufsize = gbufsize_max;
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index d9b872b9285a..9d88dd1e8421 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -268,3 +268,5 @@ config VIDEO_VIM2M
This is a virtual test device for the memory-to-memory driver
framework.
endif #V4L_TEST_DRIVERS
+
+source "drivers/media/platform/msm/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 3ec154742083..ab60119bfe52 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -49,3 +49,5 @@ obj-y += omap/
obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
ccflags-y += -I$(srctree)/drivers/media/i2c
+
+obj-y += msm/
diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig
new file mode 100644
index 000000000000..4f55c85d6025
--- /dev/null
+++ b/drivers/media/platform/msm/Kconfig
@@ -0,0 +1,7 @@
+#
+# MSM camera configuration
+#
+
+comment "Qualcomm MSM Camera And Video"
+
+source "drivers/media/platform/msm/vidc/Kconfig"
diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile
new file mode 100644
index 000000000000..ef7d98790a8e
--- /dev/null
+++ b/drivers/media/platform/msm/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the QCOM spcific video device drivers
+# based on V4L2.
+#
+
+obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/
diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig
new file mode 100644
index 000000000000..3be4cf1b60e7
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/Kconfig
@@ -0,0 +1,11 @@
+#
+# VIDEO CORE
+#
+
+menuconfig MSM_VIDC_V4L2
+ bool "Qualcomm MSM V4L2 based video driver"
+ depends on ARCH_QCOM && VIDEO_V4L2
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_DMA_CONTIG
+
+source "drivers/media/platform/msm/vidc/vmem/Kconfig"
diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile
new file mode 100644
index 000000000000..4dd6cf66861b
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/Makefile
@@ -0,0 +1,17 @@
+obj-$(CONFIG_MSM_VIDC_V4L2) := msm_v4l2_vidc.o \
+ msm_vidc_common.o \
+ msm_vidc.o \
+ msm_vdec.o \
+ msm_venc.o \
+ msm_smem.o \
+ msm_vidc_debug.o \
+ msm_vidc_res_parse.o \
+ venus_hfi.o \
+ hfi_response_handler.o \
+ hfi_packetization.o \
+ vidc_hfi.o \
+ q6_hfi.o \
+ venus_boot.o \
+ msm_vidc_dcvs.o \
+
+obj-$(CONFIG_MSM_VIDC_VMEM) += vmem/
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
new file mode 100644
index 000000000000..63c5627be971
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -0,0 +1,2048 @@
+/* Copyright (c) 2012-2015, 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/errno.h>
+#include <linux/log2.h>
+#include <linux/hash.h>
+#include <soc/qcom/ocmem.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+
+/* Set up look-up tables to convert HAL_* to HFI_*.
+ *
+ * The tables below mostly take advantage of the fact that most
+ * HAL_* types are defined bitwise. So if we index them normally
+ * when declaring the tables, we end up with huge arrays with wasted
+ * space. So before indexing them, we apply log2 to use a more
+ * sensible index.
+ */
+static int profile_table[] = {
+ [ilog2(HAL_H264_PROFILE_BASELINE)] = HFI_H264_PROFILE_BASELINE,
+ [ilog2(HAL_H264_PROFILE_MAIN)] = HFI_H264_PROFILE_MAIN,
+ [ilog2(HAL_H264_PROFILE_HIGH)] = HFI_H264_PROFILE_HIGH,
+ [ilog2(HAL_H264_PROFILE_CONSTRAINED_BASE)] =
+ HFI_H264_PROFILE_CONSTRAINED_BASE,
+ [ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
+ HFI_H264_PROFILE_CONSTRAINED_HIGH,
+ [ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
+ [ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH,
+};
+
+static int entropy_mode[] = {
+ [ilog2(HAL_H264_ENTROPY_CAVLC)] = HFI_H264_ENTROPY_CAVLC,
+ [ilog2(HAL_H264_ENTROPY_CABAC)] = HFI_H264_ENTROPY_CABAC,
+};
+
+static int cabac_model[] = {
+ [ilog2(HAL_H264_CABAC_MODEL_0)] = HFI_H264_CABAC_MODEL_0,
+ [ilog2(HAL_H264_CABAC_MODEL_1)] = HFI_H264_CABAC_MODEL_1,
+ [ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
+};
+
+static int color_format[] = {
+ [ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+ [ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+ [ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+ [ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+ [ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+ [ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+ [ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+ [ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+ [ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+ [ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+ [ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+ /* UBWC Color formats*/
+ [ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] = HFI_COLOR_FORMAT_NV12_UBWC,
+ [ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] =
+ HFI_COLOR_FORMAT_YUV420_TP10_UBWC,
+};
+
+static int nal_type[] = {
+ [ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES,
+ [ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] =
+ HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER,
+ [ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_ONE_BYTE_LENGTH,
+ [ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_TWO_BYTE_LENGTH,
+ [ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_FOUR_BYTE_LENGTH,
+};
+
+static inline int hal_to_hfi_type(int property, int hal_type)
+{
+ if (hal_type && roundup_pow_of_two(hal_type) != hal_type) {
+ /* Not a power of 2, it's not going
+ * to be in any of the tables anyway */
+ return -EINVAL;
+ }
+
+ if (hal_type)
+ hal_type = ilog2(hal_type);
+
+ switch (property) {
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ return (hal_type >= ARRAY_SIZE(profile_table)) ?
+ -ENOTSUPP : profile_table[hal_type];
+ case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+ return (hal_type >= ARRAY_SIZE(entropy_mode)) ?
+ -ENOTSUPP : entropy_mode[hal_type];
+ case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
+ return (hal_type >= ARRAY_SIZE(cabac_model)) ?
+ -ENOTSUPP : cabac_model[hal_type];
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ return (hal_type >= ARRAY_SIZE(color_format)) ?
+ -ENOTSUPP : color_format[hal_type];
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ return (hal_type >= ARRAY_SIZE(nal_type)) ?
+ -ENOTSUPP : nal_type[hal_type];
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static inline u32 get_hfi_layout(enum hal_buffer_layout_type hal_buf_layout)
+{
+ u32 hfi_layout;
+ switch (hal_buf_layout) {
+ case HAL_BUFFER_LAYOUT_TOP_BOTTOM:
+ hfi_layout = HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM;
+ break;
+ case HAL_BUFFER_LAYOUT_SEQ:
+ hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n",
+ hal_buf_layout);
+ hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+ break;
+ }
+ return hfi_layout;
+}
+
+static inline u32 get_hfi_codec(enum hal_video_codec hal_codec)
+{
+ u32 hfi_codec;
+ switch (hal_codec) {
+ case HAL_VIDEO_CODEC_MVC:
+ case HAL_VIDEO_CODEC_H264:
+ hfi_codec = HFI_VIDEO_CODEC_H264;
+ break;
+ case HAL_VIDEO_CODEC_H263:
+ hfi_codec = HFI_VIDEO_CODEC_H263;
+ break;
+ case HAL_VIDEO_CODEC_MPEG1:
+ hfi_codec = HFI_VIDEO_CODEC_MPEG1;
+ break;
+ case HAL_VIDEO_CODEC_MPEG2:
+ hfi_codec = HFI_VIDEO_CODEC_MPEG2;
+ break;
+ case HAL_VIDEO_CODEC_MPEG4:
+ hfi_codec = HFI_VIDEO_CODEC_MPEG4;
+ break;
+ case HAL_VIDEO_CODEC_DIVX_311:
+ hfi_codec = HFI_VIDEO_CODEC_DIVX_311;
+ break;
+ case HAL_VIDEO_CODEC_DIVX:
+ hfi_codec = HFI_VIDEO_CODEC_DIVX;
+ break;
+ case HAL_VIDEO_CODEC_VC1:
+ hfi_codec = HFI_VIDEO_CODEC_VC1;
+ break;
+ case HAL_VIDEO_CODEC_SPARK:
+ hfi_codec = HFI_VIDEO_CODEC_SPARK;
+ break;
+ case HAL_VIDEO_CODEC_VP8:
+ hfi_codec = HFI_VIDEO_CODEC_VP8;
+ break;
+ case HAL_VIDEO_CODEC_HEVC:
+ hfi_codec = HFI_VIDEO_CODEC_HEVC;
+ break;
+ case HAL_VIDEO_CODEC_HEVC_HYBRID:
+ hfi_codec = HFI_VIDEO_CODEC_HEVC_HYBRID;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid codec %#x\n", hal_codec);
+ hfi_codec = 0;
+ break;
+ }
+ return hfi_codec;
+}
+
+int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt,
+ u32 arch_type)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->packet_type = HFI_CMD_SYS_INIT;
+ pkt->size = sizeof(struct hfi_cmd_sys_init_packet);
+ pkt->arch_type = arch_type;
+ return rc;
+}
+
+int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->packet_type = HFI_CMD_SYS_PC_PREP;
+ pkt->size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
+ return rc;
+}
+
+int create_pkt_cmd_sys_idle_indicator(
+ struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 enable)
+{
+ struct hfi_enable *hfi;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(struct hfi_enable) + sizeof(u32);
+ pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = enable;
+ return 0;
+}
+
+int create_pkt_cmd_sys_debug_config(
+ struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode)
+{
+ struct hfi_debug_config *hfi;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(struct hfi_debug_config) + sizeof(u32);
+ pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
+ hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
+ hfi->debug_config = mode;
+ hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
+ if (msm_vidc_fw_debug_mode <= HFI_DEBUG_MODE_QDSS)
+ hfi->debug_mode = msm_vidc_fw_debug_mode;
+ return 0;
+}
+
+int create_pkt_cmd_sys_coverage_config(
+ struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "In %s(), No input packet\n", __func__);
+ return -EINVAL;
+ }
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(u32);
+ pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
+ pkt->rg_property_data[1] = mode;
+ dprintk(VIDC_DBG, "Firmware coverage mode %d\n",
+ pkt->rg_property_data[1]);
+ return 0;
+}
+
+int create_pkt_cmd_sys_set_resource(
+ struct hfi_cmd_sys_set_resource_packet *pkt,
+ struct vidc_resource_hdr *resource_hdr,
+ void *resource_value)
+{
+ int rc = 0;
+ if (!pkt || !resource_hdr || !resource_value)
+ return -EINVAL;
+
+ pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE;
+ pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet);
+ pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+ switch (resource_hdr->resource_id) {
+ case VIDC_RESOURCE_OCMEM:
+ case VIDC_RESOURCE_VMEM:
+ {
+ struct hfi_resource_ocmem *hfioc_mem =
+ (struct hfi_resource_ocmem *)
+ &pkt->rg_resource_data[0];
+
+ phys_addr_t imem_addr = (phys_addr_t)resource_value;
+
+ pkt->resource_type = HFI_RESOURCE_OCMEM;
+ pkt->size += sizeof(struct hfi_resource_ocmem) - sizeof(u32);
+ hfioc_mem->size = (u32)resource_hdr->size;
+ hfioc_mem->mem = imem_addr;
+ break;
+ }
+ default:
+ dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+ resource_hdr->resource_id);
+ rc = -ENOTSUPP;
+ }
+
+ return rc;
+}
+
+int create_pkt_cmd_sys_release_resource(
+ struct hfi_cmd_sys_release_resource_packet *pkt,
+ struct vidc_resource_hdr *resource_hdr)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_release_resource_packet);
+ pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE;
+ pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+ switch (resource_hdr->resource_id) {
+ case VIDC_RESOURCE_OCMEM:
+ case VIDC_RESOURCE_VMEM:
+ pkt->resource_type = HFI_RESOURCE_OCMEM;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+ resource_hdr->resource_id);
+ rc = -ENOTSUPP;
+ }
+
+ return rc;
+}
+
+int create_pkt_cmd_sys_ping(struct hfi_cmd_sys_ping_packet *pkt)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_ping_packet);
+ pkt->packet_type = HFI_CMD_SYS_PING;
+
+ return rc;
+}
+
+inline int create_pkt_cmd_sys_session_init(
+ struct hfi_cmd_sys_session_init_packet *pkt,
+ struct hal_session *session,
+ u32 session_domain, u32 session_codec)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_session_init_packet);
+ pkt->packet_type = HFI_CMD_SYS_SESSION_INIT;
+ pkt->session_id = hash32_ptr(session);
+ pkt->session_domain = session_domain;
+ pkt->session_codec = get_hfi_codec(session_codec);
+ if (!pkt->session_codec)
+ return -EINVAL;
+
+ return rc;
+}
+
+int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
+ int pkt_type, struct hal_session *session)
+{
+ int rc = 0;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
+ pkt->packet_type = pkt_type;
+ pkt->session_id = hash32_ptr(session);
+
+ return rc;
+}
+
+int create_pkt_cmd_sys_power_control(
+ struct hfi_cmd_sys_set_property_packet *pkt, u32 enable)
+{
+ struct hfi_enable *hfi;
+ if (!pkt) {
+ dprintk(VIDC_ERR, "No input packet\n");
+ return -EINVAL;
+ }
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(struct hfi_enable) + sizeof(u32);
+ pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = enable;
+ return 0;
+}
+
+static u32 get_hfi_buffer(int hal_buffer)
+{
+ u32 buffer;
+ switch (hal_buffer) {
+ case HAL_BUFFER_INPUT:
+ buffer = HFI_BUFFER_INPUT;
+ break;
+ case HAL_BUFFER_OUTPUT:
+ buffer = HFI_BUFFER_OUTPUT;
+ break;
+ case HAL_BUFFER_OUTPUT2:
+ buffer = HFI_BUFFER_OUTPUT2;
+ break;
+ case HAL_BUFFER_EXTRADATA_INPUT:
+ buffer = HFI_BUFFER_EXTRADATA_INPUT;
+ break;
+ case HAL_BUFFER_EXTRADATA_OUTPUT:
+ buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
+ break;
+ case HAL_BUFFER_EXTRADATA_OUTPUT2:
+ buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+ break;
+ case HAL_BUFFER_INTERNAL_SCRATCH:
+ buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+ break;
+ case HAL_BUFFER_INTERNAL_SCRATCH_1:
+ buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+ break;
+ case HAL_BUFFER_INTERNAL_SCRATCH_2:
+ buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+ break;
+ case HAL_BUFFER_INTERNAL_PERSIST:
+ buffer = HFI_BUFFER_INTERNAL_PERSIST;
+ break;
+ case HAL_BUFFER_INTERNAL_PERSIST_1:
+ buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid buffer: %#x\n",
+ hal_buffer);
+ buffer = 0;
+ break;
+ }
+ return buffer;
+}
+
+static int get_hfi_extradata_index(enum hal_extradata_id index)
+{
+ int ret = 0;
+ switch (index) {
+ case HAL_EXTRADATA_MB_QUANTIZATION:
+ ret = HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION;
+ break;
+ case HAL_EXTRADATA_INTERLACE_VIDEO:
+ ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_VC1_FRAMEDISP:
+ ret = HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_VC1_SEQDISP:
+ ret = HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_TIMESTAMP:
+ ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_S3D_FRAME_PACKING:
+ ret = HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_FRAME_RATE:
+ ret = HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_PANSCAN_WINDOW:
+ ret = HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_RECOVERY_POINT_SEI:
+ ret = HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_MULTISLICE_INFO:
+ ret = HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO;
+ break;
+ case HAL_EXTRADATA_NUM_CONCEALED_MB:
+ ret = HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB;
+ break;
+ case HAL_EXTRADATA_ASPECT_RATIO:
+ case HAL_EXTRADATA_INPUT_CROP:
+ case HAL_EXTRADATA_DIGITAL_ZOOM:
+ ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_MPEG2_SEQDISP:
+ ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_STREAM_USERDATA:
+ ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_FRAME_QP:
+ ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_FRAME_BITS_INFO:
+ ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA;
+ break;
+ case HAL_EXTRADATA_LTR_INFO:
+ ret = HFI_PROPERTY_PARAM_VENC_LTR_INFO;
+ break;
+ case HAL_EXTRADATA_METADATA_MBI:
+ ret = HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+ break;
+ default:
+ dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
+ break;
+ }
+ return ret;
+}
+
+static int get_hfi_extradata_id(enum hal_extradata_id index)
+{
+ int ret = 0;
+ switch (index) {
+ case HAL_EXTRADATA_ASPECT_RATIO:
+ ret = MSM_VIDC_EXTRADATA_ASPECT_RATIO;
+ break;
+ case HAL_EXTRADATA_INPUT_CROP:
+ ret = MSM_VIDC_EXTRADATA_INPUT_CROP;
+ break;
+ case HAL_EXTRADATA_DIGITAL_ZOOM:
+ ret = MSM_VIDC_EXTRADATA_DIGITAL_ZOOM;
+ break;
+ default:
+ ret = get_hfi_extradata_index(index);
+ break;
+ }
+ return ret;
+}
+
+static u32 get_hfi_buf_mode(enum buffer_mode_type hal_buf_mode)
+{
+ u32 buf_mode;
+ switch (hal_buf_mode) {
+ case HAL_BUFFER_MODE_STATIC:
+ buf_mode = HFI_BUFFER_MODE_STATIC;
+ break;
+ case HAL_BUFFER_MODE_RING:
+ buf_mode = HFI_BUFFER_MODE_RING;
+ break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid buffer mode: %#x\n",
+ hal_buf_mode);
+ buf_mode = 0;
+ break;
+ }
+ return buf_mode;
+}
+
+static u32 get_hfi_ltr_mode(enum ltr_mode ltr_mode_type)
+{
+ u32 ltrmode;
+ switch (ltr_mode_type) {
+ case HAL_LTR_MODE_DISABLE:
+ ltrmode = HFI_LTR_MODE_DISABLE;
+ break;
+ case HAL_LTR_MODE_MANUAL:
+ ltrmode = HFI_LTR_MODE_MANUAL;
+ break;
+ case HAL_LTR_MODE_PERIODIC:
+ ltrmode = HFI_LTR_MODE_PERIODIC;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n",
+ ltr_mode_type);
+ ltrmode = HFI_LTR_MODE_DISABLE;
+ break;
+ }
+ return ltrmode;
+}
+
+int create_pkt_cmd_session_set_buffers(
+ struct hfi_cmd_session_set_buffers_packet *pkt,
+ struct hal_session *session,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ int rc = 0;
+ int i = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS;
+ pkt->session_id = hash32_ptr(session);
+ pkt->buffer_size = buffer_info->buffer_size;
+ pkt->min_buffer_size = buffer_info->buffer_size;
+ pkt->num_buffers = buffer_info->num_buffers;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+ buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+ struct hfi_buffer_info *buff;
+ pkt->extra_data_size = buffer_info->extradata_size;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+ sizeof(u32) + (buffer_info->num_buffers *
+ sizeof(struct hfi_buffer_info));
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ for (i = 0; i < pkt->num_buffers; i++) {
+ buff->buffer_addr =
+ (u32)buffer_info->align_device_addr;
+ buff->extra_data_addr =
+ (u32)buffer_info->extradata_addr;
+ }
+ } else {
+ pkt->extra_data_size = 0;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ for (i = 0; i < pkt->num_buffers; i++) {
+ pkt->rg_buffer_info[i] =
+ (u32)buffer_info->align_device_addr;
+ }
+ }
+
+ pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+ if (!pkt->buffer_type)
+ return -EINVAL;
+
+ return rc;
+}
+
+int create_pkt_cmd_session_release_buffers(
+ struct hfi_cmd_session_release_buffer_packet *pkt,
+ struct hal_session *session,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ int rc = 0;
+ int i = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
+ pkt->session_id = hash32_ptr(session);
+ pkt->buffer_size = buffer_info->buffer_size;
+ pkt->num_buffers = buffer_info->num_buffers;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+ buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ for (i = 0; i < pkt->num_buffers; i++) {
+ buff->buffer_addr =
+ (u32)buffer_info->align_device_addr;
+ buff->extra_data_addr =
+ (u32)buffer_info->extradata_addr;
+ }
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+ sizeof(u32) + (buffer_info->num_buffers *
+ sizeof(struct hfi_buffer_info));
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++) {
+ pkt->rg_buffer_info[i] =
+ (u32)buffer_info->align_device_addr;
+ }
+ pkt->extra_data_size = 0;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ }
+ pkt->response_req = buffer_info->response_required;
+ pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+ if (!pkt->buffer_type)
+ return -EINVAL;
+ return rc;
+}
+
+int create_pkt_cmd_session_etb_decoder(
+ struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+ struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+ int rc = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->size =
+ sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet);
+ pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+ pkt->session_id = hash32_ptr(session);
+ pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+ pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+ pkt->flags = input_frame->flags;
+ pkt->mark_target = input_frame->mark_target;
+ pkt->mark_data = input_frame->mark_data;
+ pkt->offset = input_frame->offset;
+ pkt->alloc_len = input_frame->alloc_len;
+ pkt->filled_len = input_frame->filled_len;
+ pkt->input_tag = input_frame->clnt_data;
+ pkt->packet_buffer = (u32)input_frame->device_addr;
+
+ trace_msm_v4l2_vidc_buffer_event_start("ETB",
+ input_frame->device_addr, input_frame->timestamp,
+ input_frame->alloc_len, input_frame->filled_len,
+ input_frame->offset);
+
+ if (!pkt->packet_buffer)
+ rc = -EINVAL;
+ return rc;
+}
+
+int create_pkt_cmd_session_etb_encoder(
+ struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt,
+ struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+ int rc = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
+ pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+ pkt->session_id = hash32_ptr(session);
+ pkt->view_id = 0;
+ pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+ pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+ pkt->flags = input_frame->flags;
+ pkt->mark_target = input_frame->mark_target;
+ pkt->mark_data = input_frame->mark_data;
+ pkt->offset = input_frame->offset;
+ pkt->alloc_len = input_frame->alloc_len;
+ pkt->filled_len = input_frame->filled_len;
+ pkt->input_tag = input_frame->clnt_data;
+ pkt->packet_buffer = (u32)input_frame->device_addr;
+ pkt->extra_data_buffer = (u32)input_frame->extradata_addr;
+
+ trace_msm_v4l2_vidc_buffer_event_start("ETB",
+ input_frame->device_addr, input_frame->timestamp,
+ input_frame->alloc_len, input_frame->filled_len,
+ input_frame->offset);
+
+ if (!pkt->packet_buffer)
+ rc = -EINVAL;
+ return rc;
+}
+
+int create_pkt_cmd_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt,
+ struct hal_session *session,
+ struct vidc_frame_data *output_frame)
+{
+ int rc = 0;
+ if (!pkt || !session || !output_frame)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet);
+ pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER;
+ pkt->session_id = hash32_ptr(session);
+
+ if (output_frame->buffer_type == HAL_BUFFER_OUTPUT)
+ pkt->stream_id = 0;
+ else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2)
+ pkt->stream_id = 1;
+
+ if (!output_frame->device_addr)
+ return -EINVAL;
+
+ pkt->packet_buffer = (u32)output_frame->device_addr;
+ pkt->extra_data_buffer = (u32)output_frame->extradata_addr;
+ pkt->alloc_len = output_frame->alloc_len;
+ pkt->filled_len = output_frame->filled_len;
+ pkt->offset = output_frame->offset;
+ pkt->rgData[0] = output_frame->extradata_size;
+
+ trace_msm_v4l2_vidc_buffer_event_start("FTB",
+ output_frame->device_addr, output_frame->timestamp,
+ output_frame->alloc_len, output_frame->filled_len,
+ output_frame->offset);
+ dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
+ pkt->alloc_len, pkt->filled_len, pkt->offset);
+
+ return rc;
+}
+
+int create_pkt_cmd_session_parse_seq_header(
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+ struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+ int rc = 0;
+ if (!pkt || !session || !seq_hdr)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_parse_sequence_header_packet);
+ pkt->packet_type = HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER;
+ pkt->session_id = hash32_ptr(session);
+ pkt->header_len = seq_hdr->seq_hdr_len;
+ if (!seq_hdr->seq_hdr)
+ return -EINVAL;
+ pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+ return rc;
+}
+
+int create_pkt_cmd_session_get_seq_hdr(
+ struct hfi_cmd_session_get_sequence_header_packet *pkt,
+ struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+ int rc = 0;
+
+ if (!pkt || !session || !seq_hdr)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_get_sequence_header_packet);
+ pkt->packet_type = HFI_CMD_SESSION_GET_SEQUENCE_HEADER;
+ pkt->session_id = hash32_ptr(session);
+ pkt->buffer_len = seq_hdr->seq_hdr_len;
+ if (!seq_hdr->seq_hdr)
+ return -EINVAL;
+ pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+ return rc;
+}
+
+int create_pkt_cmd_session_get_buf_req(
+ struct hfi_cmd_session_get_property_packet *pkt,
+ struct hal_session *session)
+{
+ int rc = 0;
+
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+ pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+ pkt->session_id = hash32_ptr(session);
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
+
+ return rc;
+}
+
+int create_pkt_cmd_session_flush(struct hfi_cmd_session_flush_packet *pkt,
+ struct hal_session *session, enum hal_flush flush_mode)
+{
+ int rc = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_flush_packet);
+ pkt->packet_type = HFI_CMD_SESSION_FLUSH;
+ pkt->session_id = hash32_ptr(session);
+ switch (flush_mode) {
+ case HAL_FLUSH_INPUT:
+ pkt->flush_type = HFI_FLUSH_INPUT;
+ break;
+ case HAL_FLUSH_OUTPUT:
+ pkt->flush_type = HFI_FLUSH_OUTPUT;
+ break;
+ case HAL_FLUSH_OUTPUT2:
+ pkt->flush_type = HFI_FLUSH_OUTPUT2;
+ break;
+ case HAL_FLUSH_ALL:
+ pkt->flush_type = HFI_FLUSH_ALL;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid flush mode: %#x\n", flush_mode);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+int create_pkt_cmd_session_get_property(
+ struct hfi_cmd_session_get_property_packet *pkt,
+ struct hal_session *session, enum hal_property ptype)
+{
+ int rc = 0;
+ if (!pkt || !session) {
+ dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+ pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+ pkt->session_id = hash32_ptr(session);
+ pkt->num_properties = 1;
+ switch (ptype) {
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ break;
+ default:
+ dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
+ ptype);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+int create_pkt_cmd_session_set_property(
+ struct hfi_cmd_session_set_property_packet *pkt,
+ struct hal_session *session,
+ enum hal_property ptype, void *pdata)
+{
+ int rc = 0;
+ if (!pkt || !session)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
+ pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+ pkt->session_id = hash32_ptr(session);
+ pkt->num_properties = 1;
+
+ switch (ptype) {
+ case HAL_CONFIG_FRAME_RATE:
+ {
+ u32 buffer_type;
+ struct hfi_frame_rate *hfi;
+ struct hal_frame_rate *prop = (struct hal_frame_rate *) pdata;
+
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE;
+ hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+
+ hfi->frame_rate = prop->frame_rate;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate);
+ break;
+ }
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ {
+ u32 buffer_type;
+ struct hfi_uncompressed_format_select *hfi;
+ struct hal_uncompressed_format_select *prop =
+ (struct hal_uncompressed_format_select *) pdata;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
+
+ hfi = (struct hfi_uncompressed_format_select *)
+ &pkt->rg_property_data[1];
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+ hfi->format = hal_to_hfi_type(
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ prop->format);
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_uncompressed_format_select);
+ break;
+ }
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+ break;
+ case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+ break;
+ case HAL_PARAM_FRAME_SIZE:
+ {
+ struct hfi_frame_size *hfi;
+ struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
+ u32 buffer_type;
+
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE;
+ hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+
+ hfi->height = prop->height;
+ hfi->width = prop->width;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+ break;
+ }
+ case HAL_CONFIG_REALTIME:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_REALTIME;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+ {
+ struct hfi_buffer_count_actual *hfi;
+ struct hal_buffer_count_actual *prop =
+ (struct hal_buffer_count_actual *) pdata;
+ u32 buffer_type;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
+ hfi = (struct hfi_buffer_count_actual *)
+ &pkt->rg_property_data[1];
+ hfi->buffer_count_actual = prop->buffer_count_actual;
+
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_buffer_count_actual);
+
+ break;
+ }
+ case HAL_PARAM_BUFFER_SIZE_ACTUAL:
+ {
+ struct hfi_buffer_size_actual *hfi;
+ struct hal_buffer_size_actual *prop =
+ (struct hal_buffer_size_actual *) pdata;
+ u32 buffer_type;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL;
+
+ hfi = (struct hfi_buffer_size_actual *)
+ &pkt->rg_property_data[1];
+ hfi->buffer_size = prop->buffer_size;
+
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_buffer_count_actual);
+ break;
+ }
+ case HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL:
+ {
+ struct hfi_buffer_display_hold_count_actual *hfi;
+ struct hal_buffer_display_hold_count_actual *prop =
+ (struct hal_buffer_display_hold_count_actual *) pdata;
+ u32 buffer_type;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL;
+
+ hfi = (struct hfi_buffer_display_hold_count_actual *)
+ &pkt->rg_property_data[1];
+ hfi->hold_count = prop->hold_count;
+
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_buffer_count_actual);
+ break;
+ }
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ {
+ struct hfi_nal_stream_format_select *hfi;
+ struct hal_nal_stream_format_select *prop =
+ (struct hal_nal_stream_format_select *)pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
+ hfi = (struct hfi_nal_stream_format_select *)
+ &pkt->rg_property_data[1];
+ dprintk(VIDC_DBG, "data is :%d\n",
+ prop->nal_stream_format_select);
+ hfi->nal_stream_format_select = hal_to_hfi_type(
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+ prop->nal_stream_format_select);
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_nal_stream_format_select);
+ break;
+ }
+ case HAL_PARAM_VDEC_OUTPUT_ORDER:
+ {
+ int *data = (int *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
+ switch (*data) {
+ case HAL_OUTPUT_ORDER_DECODE:
+ pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE;
+ break;
+ case HAL_OUTPUT_ORDER_DISPLAY:
+ pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
+ break;
+ default:
+ dprintk(VIDC_ERR, "invalid output order: %#x\n",
+ *data);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+ {
+ struct hfi_enable_picture *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
+ hfi->picture_type =
+ ((struct hfi_enable_picture *)pdata)->picture_type;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_MULTI_STREAM:
+ {
+ struct hfi_multi_stream *hfi;
+ struct hal_multi_stream *prop =
+ (struct hal_multi_stream *) pdata;
+ u32 buffer_type;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+ hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1];
+
+ buffer_type = get_hfi_buffer(prop->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+ hfi->enable = prop->enable;
+ hfi->width = prop->width;
+ hfi->height = prop->height;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream);
+ break;
+ }
+ case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+ {
+ struct hfi_display_picture_buffer_count *hfi;
+ struct hal_display_picture_buffer_count *prop =
+ (struct hal_display_picture_buffer_count *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT;
+ hfi = (struct hfi_display_picture_buffer_count *)
+ &pkt->rg_property_data[1];
+ hfi->count = prop->count;
+ hfi->enable = prop->enable;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_display_picture_buffer_count);
+ break;
+ }
+ case HAL_PARAM_DIVX_FORMAT:
+ {
+ int *data = pdata;
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT;
+ switch (*data) {
+ case HAL_DIVX_FORMAT_4:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_4;
+ break;
+ case HAL_DIVX_FORMAT_5:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_5;
+ break;
+ case HAL_DIVX_FORMAT_6:
+ pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid divx format: %#x\n", *data);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_SYNC_FRAME_DECODE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VENC_REQUEST_IFRAME:
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
+ pkt->size += sizeof(u32);
+ break;
+ case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+ break;
+ case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+ break;
+ case HAL_CONFIG_VENC_TARGET_BITRATE:
+ {
+ struct hfi_bitrate *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+ hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+ hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+ hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+ break;
+ }
+ case HAL_CONFIG_VENC_MAX_BITRATE:
+ {
+ struct hfi_bitrate *hfi;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
+ hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+ hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+ hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+
+ pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+ break;
+ }
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ {
+ struct hfi_profile_level *hfi;
+ struct hal_profile_level *prop =
+ (struct hal_profile_level *) pdata;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ hfi = (struct hfi_profile_level *)
+ &pkt->rg_property_data[1];
+ hfi->level = prop->level;
+ hfi->profile = hal_to_hfi_type(HAL_PARAM_PROFILE_LEVEL_CURRENT,
+ prop->profile);
+ if (hfi->profile <= 0) {
+ hfi->profile = HFI_H264_PROFILE_HIGH;
+ dprintk(VIDC_WARN,
+ "Profile %d not supported, falling back to high\n",
+ prop->profile);
+ }
+
+ if (!hfi->level) {
+ hfi->level = 1;
+ dprintk(VIDC_WARN,
+ "Level %d not supported, falling back to high\n",
+ prop->level);
+ }
+
+ pkt->size += sizeof(u32) + sizeof(struct hfi_profile_level);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+ {
+ struct hfi_h264_entropy_control *hfi;
+ struct hal_h264_entropy_control *prop =
+ (struct hal_h264_entropy_control *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
+ hfi = (struct hfi_h264_entropy_control *)
+ &pkt->rg_property_data[1];
+ hfi->entropy_mode = hal_to_hfi_type(
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+ prop->entropy_mode);
+ if (hfi->entropy_mode == HAL_H264_ENTROPY_CABAC)
+ hfi->cabac_model = hal_to_hfi_type(
+ HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+ prop->cabac_model);
+ pkt->size += sizeof(u32) + sizeof(
+ struct hfi_h264_entropy_control);
+ break;
+ }
+ case HAL_PARAM_VENC_RATE_CONTROL:
+ {
+ u32 *rc;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
+ rc = (u32 *)pdata;
+ switch ((enum hal_rate_control) *rc) {
+ case HAL_RATE_CONTROL_OFF:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
+ break;
+ case HAL_RATE_CONTROL_CBR_CFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR;
+ break;
+ case HAL_RATE_CONTROL_CBR_VFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR;
+ break;
+ case HAL_RATE_CONTROL_VBR_CFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
+ break;
+ case HAL_RATE_CONTROL_VBR_VFR:
+ pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Invalid Rate control setting: %p\n",
+ pdata);
+ break;
+ }
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+ {
+ struct hfi_mpeg4_time_resolution *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+ hfi = (struct hfi_mpeg4_time_resolution *)
+ &pkt->rg_property_data[1];
+ hfi->time_increment_resolution =
+ ((struct hal_mpeg4_time_resolution *)pdata)->
+ time_increment_resolution;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+ {
+ struct hfi_mpeg4_header_extension *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION;
+ hfi = (struct hfi_mpeg4_header_extension *)
+ &pkt->rg_property_data[1];
+ hfi->header_extension = (u32)(unsigned long) pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+ {
+ struct hfi_h264_db_control *hfi;
+ struct hal_h264_db_control *prop =
+ (struct hal_h264_db_control *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1];
+ switch (prop->mode) {
+ case HAL_H264_DB_MODE_DISABLE:
+ hfi->mode = HFI_H264_DB_MODE_DISABLE;
+ break;
+ case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY:
+ hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+ break;
+ case HAL_H264_DB_MODE_ALL_BOUNDARY:
+ hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid deblocking mode: %#x\n",
+ prop->mode);
+ break;
+ }
+ hfi->slice_alpha_offset = prop->slice_alpha_offset;
+ hfi->slice_beta_offset = prop->slice_beta_offset;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_h264_db_control);
+ break;
+ }
+ case HAL_PARAM_VENC_SESSION_QP:
+ {
+ struct hfi_quantization *hfi;
+ struct hal_quantization *hal_quant =
+ (struct hal_quantization *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SESSION_QP;
+ hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
+ hfi->qp_i = hal_quant->qpi;
+ hfi->qp_p = hal_quant->qpp;
+ hfi->qp_b = hal_quant->qpb;
+ hfi->layer_id = hal_quant->layer_id;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
+ break;
+ }
+ case HAL_PARAM_VENC_SESSION_QP_RANGE:
+ {
+ struct hfi_quantization_range *hfi;
+ struct hfi_quantization_range *hal_range =
+ (struct hfi_quantization_range *) pdata;
+ u32 min_qp, max_qp;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+ hfi = (struct hfi_quantization_range *)
+ &pkt->rg_property_data[1];
+
+ min_qp = hal_range->min_qp;
+ max_qp = hal_range->max_qp;
+
+ /* We'll be packing in the qp, so make sure we
+ * won't be losing data when masking */
+ if (min_qp > 0xff || max_qp > 0xff) {
+ dprintk(VIDC_ERR, "qp value out of range\n");
+ rc = -ERANGE;
+ break;
+ }
+
+ /* When creating the packet, pack the qp value as
+ * 0xiippbb, where ii = qp range for I-frames,
+ * pp = qp range for P-frames, etc. */
+ hfi->min_qp = min_qp | min_qp << 8 | min_qp << 16;
+ hfi->max_qp = max_qp | max_qp << 8 | max_qp << 16;
+ hfi->layer_id = hal_range->layer_id;
+
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_quantization_range);
+ break;
+ }
+ case HAL_PARAM_VENC_SEARCH_RANGE:
+ {
+ struct hfi_vc1e_perf_cfg_type *hfi;
+ struct hal_vc1e_perf_cfg_type *hal_mv_searchrange =
+ (struct hal_vc1e_perf_cfg_type *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG;
+ hfi = (struct hfi_vc1e_perf_cfg_type *)
+ &pkt->rg_property_data[1];
+ hfi->search_range_x_subsampled[0] =
+ hal_mv_searchrange->i_frame.x_subsampled;
+ hfi->search_range_x_subsampled[1] =
+ hal_mv_searchrange->p_frame.x_subsampled;
+ hfi->search_range_x_subsampled[2] =
+ hal_mv_searchrange->b_frame.x_subsampled;
+ hfi->search_range_y_subsampled[0] =
+ hal_mv_searchrange->i_frame.y_subsampled;
+ hfi->search_range_y_subsampled[1] =
+ hal_mv_searchrange->p_frame.y_subsampled;
+ hfi->search_range_y_subsampled[2] =
+ hal_mv_searchrange->b_frame.y_subsampled;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_vc1e_perf_cfg_type);
+ break;
+ }
+ case HAL_PARAM_VENC_MAX_NUM_B_FRAMES:
+ {
+ struct hfi_max_num_b_frames *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES;
+ hfi = (struct hfi_max_num_b_frames *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_max_num_b_frames *) pdata,
+ sizeof(struct hfi_max_num_b_frames));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_max_num_b_frames);
+ break;
+ }
+ case HAL_CONFIG_VENC_INTRA_PERIOD:
+ {
+ struct hfi_intra_period *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD;
+ hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_intra_period *) pdata,
+ sizeof(struct hfi_intra_period));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_intra_period);
+ break;
+ }
+ case HAL_CONFIG_VENC_IDR_PERIOD:
+ {
+ struct hfi_idr_period *hfi;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
+ hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1];
+ hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_CONCEAL_COLOR:
+ {
+ struct hfi_conceal_color *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+ hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+ if (hfi)
+ hfi->conceal_color =
+ ((struct hfi_conceal_color *) pdata)->
+ conceal_color;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VPE_OPERATIONS:
+ {
+ struct hfi_operations_type *hfi;
+ struct hal_operations *prop =
+ (struct hal_operations *) pdata;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
+ hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+ switch (prop->rotate) {
+ case HAL_ROTATE_NONE:
+ hfi->rotation = HFI_ROTATE_NONE;
+ break;
+ case HAL_ROTATE_90:
+ hfi->rotation = HFI_ROTATE_90;
+ break;
+ case HAL_ROTATE_180:
+ hfi->rotation = HFI_ROTATE_180;
+ break;
+ case HAL_ROTATE_270:
+ hfi->rotation = HFI_ROTATE_270;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid rotation setting: %#x\n",
+ prop->rotate);
+ rc = -EINVAL;
+ break;
+ }
+ switch (prop->flip) {
+ case HAL_FLIP_NONE:
+ hfi->flip = HFI_FLIP_NONE;
+ break;
+ case HAL_FLIP_HORIZONTAL:
+ hfi->flip = HFI_FLIP_HORIZONTAL;
+ break;
+ case HAL_FLIP_VERTICAL:
+ hfi->flip = HFI_FLIP_VERTICAL;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid flip setting: %#x\n",
+ prop->flip);
+ rc = -EINVAL;
+ break;
+ }
+ pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
+ break;
+ }
+ case HAL_PARAM_VENC_INTRA_REFRESH:
+ {
+ struct hfi_intra_refresh *hfi;
+ struct hal_intra_refresh *prop =
+ (struct hal_intra_refresh *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+ hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1];
+ switch (prop->mode) {
+ case HAL_INTRA_REFRESH_NONE:
+ hfi->mode = HFI_INTRA_REFRESH_NONE;
+ break;
+ case HAL_INTRA_REFRESH_ADAPTIVE:
+ hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+ break;
+ case HAL_INTRA_REFRESH_CYCLIC:
+ hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+ break;
+ case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+ hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+ break;
+ case HAL_INTRA_REFRESH_RANDOM:
+ hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Invalid intra refresh setting: %#x\n",
+ prop->mode);
+ break;
+ }
+ hfi->air_mbs = prop->air_mbs;
+ hfi->air_ref = prop->air_ref;
+ hfi->cir_mbs = prop->cir_mbs;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_intra_refresh);
+ break;
+ }
+ case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+ {
+ struct hfi_multi_slice_control *hfi;
+ struct hal_multi_slice_control *prop =
+ (struct hal_multi_slice_control *) pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL;
+ hfi = (struct hfi_multi_slice_control *)
+ &pkt->rg_property_data[1];
+ switch (prop->multi_slice) {
+ case HAL_MULTI_SLICE_OFF:
+ hfi->multi_slice = HFI_MULTI_SLICE_OFF;
+ break;
+ case HAL_MULTI_SLICE_GOB:
+ hfi->multi_slice = HFI_MULTI_SLICE_GOB;
+ break;
+ case HAL_MULTI_SLICE_BY_MB_COUNT:
+ hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT;
+ break;
+ case HAL_MULTI_SLICE_BY_BYTE_COUNT:
+ hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid slice settings: %#x\n",
+ prop->multi_slice);
+ break;
+ }
+ hfi->slice_size = prop->slice_size;
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_multi_slice_control);
+ break;
+ }
+ case HAL_PARAM_INDEX_EXTRADATA:
+ {
+ struct hfi_index_extradata_config *hfi;
+ struct hal_extradata_enable *extra = pdata;
+ int id = 0;
+ pkt->rg_property_data[0] =
+ get_hfi_extradata_index(extra->index);
+ hfi =
+ (struct hfi_index_extradata_config *)
+ &pkt->rg_property_data[1];
+ hfi->enable = extra->enable;
+ id = get_hfi_extradata_id(extra->index);
+ if (id)
+ hfi->index_extra_data_id = id;
+ else {
+ dprintk(VIDC_WARN,
+ "Failed to find extradata id: %d\n",
+ id);
+ rc = -EINVAL;
+ }
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_index_extradata_config);
+ break;
+ }
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hal_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_VUI_TIMING_INFO:
+ {
+ struct hfi_h264_vui_timing_info *hfi;
+ struct hal_h264_vui_timing_info *timing_info = pdata;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
+
+ hfi = (struct hfi_h264_vui_timing_info *)&pkt->
+ rg_property_data[1];
+ hfi->enable = timing_info->enable;
+ hfi->fixed_frame_rate = timing_info->fixed_frame_rate;
+ hfi->time_scale = timing_info->time_scale;
+
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_h264_vui_timing_info);
+ break;
+ }
+ case HAL_CONFIG_VPE_DEINTERLACE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VPE_DEINTERLACE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hal_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_GENERATE_AUDNAL:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hal_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_BUFFER_ALLOC_MODE:
+ {
+ u32 buffer_type;
+ u32 buffer_mode;
+ struct hfi_buffer_alloc_mode *hfi;
+ struct hal_buffer_alloc_mode *alloc_info = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
+ hfi = (struct hfi_buffer_alloc_mode *)
+ &pkt->rg_property_data[1];
+ buffer_type = get_hfi_buffer(alloc_info->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+ buffer_mode = get_hfi_buf_mode(alloc_info->buffer_mode);
+ if (buffer_mode)
+ hfi->buffer_mode = buffer_mode;
+ else
+ return -EINVAL;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_buffer_alloc_mode);
+ break;
+ }
+ case HAL_PARAM_VDEC_FRAME_ASSEMBLY:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC:
+ {
+ struct hfi_enable *hfi;
+ struct hal_h264_vui_bitstream_restrc *hal = pdata;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = hal->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY:
+ {
+ struct hfi_enable *hfi;
+ struct hal_preserve_text_quality *hal = pdata;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = hal->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VDEC_SCS_THRESHOLD:
+ {
+ struct hfi_scs_threshold *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD;
+ hfi = (struct hfi_scs_threshold *) &pkt->rg_property_data[1];
+ hfi->threshold_value =
+ ((struct hfi_scs_threshold *) pdata)->threshold_value;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_scs_threshold);
+ break;
+ }
+ case HAL_PARAM_MVC_BUFFER_LAYOUT:
+ {
+ struct hfi_mvc_buffer_layout_descp_type *hfi;
+ struct hal_mvc_buffer_layout *layout_info = pdata;
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT;
+ hfi = (struct hfi_mvc_buffer_layout_descp_type *)
+ &pkt->rg_property_data[1];
+ hfi->layout_type = get_hfi_layout(layout_info->layout_type);
+ hfi->bright_view_first = layout_info->bright_view_first;
+ hfi->ngap = layout_info->ngap;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_mvc_buffer_layout_descp_type);
+ break;
+ }
+ case HAL_PARAM_VENC_LTRMODE:
+ {
+ struct hfi_ltr_mode *hfi;
+ struct hal_ltr_mode *hal = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_LTRMODE;
+ hfi = (struct hfi_ltr_mode *) &pkt->rg_property_data[1];
+ hfi->ltr_mode = get_hfi_ltr_mode(hal->mode);
+ hfi->ltr_count = hal->count;
+ hfi->trust_mode = hal->trust_mode;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mode);
+ break;
+ }
+ case HAL_CONFIG_VENC_USELTRFRAME:
+ {
+ struct hfi_ltr_use *hfi;
+ struct hal_ltr_use *hal = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_USELTRFRAME;
+ hfi = (struct hfi_ltr_use *) &pkt->rg_property_data[1];
+ hfi->frames = hal->frames;
+ hfi->ref_ltr = hal->ref_ltr;
+ hfi->use_constrnt = hal->use_constraint;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_use);
+ break;
+ }
+ case HAL_CONFIG_VENC_MARKLTRFRAME:
+ {
+ struct hfi_ltr_mark *hfi;
+ struct hal_ltr_mark *hal = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME;
+ hfi = (struct hfi_ltr_mark *) &pkt->rg_property_data[1];
+ hfi->mark_frame = hal->mark_frame;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mark);
+ break;
+ }
+ case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+ pkt->rg_property_data[1] = *(u32 *)pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
+ pkt->rg_property_data[1] = *(u32 *)pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP;
+ hfi = (struct hfi_enable *)&pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *)pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_ENABLE_INITIAL_QP:
+ {
+ struct hfi_initial_quantization *hfi;
+ struct hal_initial_quantization *quant = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_INITIAL_QP;
+ hfi = (struct hfi_initial_quantization *)
+ &pkt->rg_property_data[1];
+ hfi->init_qp_enable = quant->init_qp_enable;
+ hfi->qp_i = quant->qpi;
+ hfi->qp_p = quant->qpp;
+ hfi->qp_b = quant->qpb;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_initial_quantization);
+ break;
+ }
+ case HAL_PARAM_VPE_COLOR_SPACE_CONVERSION:
+ {
+ struct hfi_vpe_color_space_conversion *hfi = NULL;
+ struct hal_vpe_color_space_conversion *hal = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION;
+ hfi = (struct hfi_vpe_color_space_conversion *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi->csc_matrix, hal->csc_matrix,
+ sizeof(hfi->csc_matrix));
+ memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias));
+ memcpy(hfi->csc_limit, hal->csc_limit, sizeof(hfi->csc_limit));
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_vpe_color_space_conversion);
+ break;
+ }
+ case HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE:
+ {
+ struct hfi_enable *hfi;
+ struct hal_enable *err_res = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE;
+ hfi = (struct hfi_enable *)&pkt->rg_property_data[1];
+ hfi->enable = err_res->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_NAL_SVC_EXT:
+ {
+ struct hfi_enable *hfi;
+ struct hal_enable *svc_nal = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT;
+ hfi = (struct hfi_enable *)&pkt->rg_property_data[1];
+ hfi->enable = svc_nal->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_CONFIG_VENC_PERF_MODE:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+ pkt->rg_property_data[1] = *(u32 *)pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER;
+ pkt->rg_property_data[1] = *(u32 *)pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_PARAM_VDEC_NON_SECURE_OUTPUT2:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VENC_HIER_P_HYBRID_MODE:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE;
+ pkt->rg_property_data[1] =
+ ((struct hfi_hybrid_hierp *)pdata)->layers;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_hybrid_hierp);
+ break;
+ }
+ /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
+ case HAL_CONFIG_BUFFER_REQUIREMENTS:
+ case HAL_CONFIG_PRIORITY:
+ case HAL_CONFIG_BATCH_INFO:
+ case HAL_PARAM_METADATA_PASS_THROUGH:
+ case HAL_SYS_IDLE_INDICATOR:
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+ case HAL_PARAM_CHROMA_SITE:
+ case HAL_PARAM_PROPERTIES_SUPPORTED:
+ case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+ case HAL_PARAM_CAPABILITY_SUPPORTED:
+ case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ case HAL_PARAM_MULTI_VIEW_FORMAT:
+ case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ case HAL_PARAM_CODEC_SUPPORTED:
+ case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+ case HAL_PARAM_VDEC_MB_QUANTIZATION:
+ case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+ case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+ case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+ case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+ case HAL_CONFIG_VDEC_MULTI_STREAM:
+ case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+ case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+ case HAL_PARAM_VENC_LOW_LATENCY:
+ default:
+ dprintk(VIDC_ERR, "DEFAULT: Calling %#x\n", ptype);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
+
+static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
+{
+ int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+ switch (type) {
+ case SSR_ERR_FATAL:
+ rc = HFI_TEST_SSR_SW_ERR_FATAL;
+ break;
+ case SSR_SW_DIV_BY_ZERO:
+ rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
+ break;
+ case SSR_HW_WDOG_IRQ:
+ rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "SSR trigger type not recognized, using WDOG.\n");
+ }
+ return rc;
+}
+
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+ struct hfi_cmd_sys_test_ssr_packet *pkt)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "Invalid params, device: %p\n", pkt);
+ return -EINVAL;
+ }
+ pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
+ pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
+ pkt->trigger_type = get_hfi_ssr_type(type);
+ return 0;
+}
+
+int create_pkt_cmd_sys_image_version(
+ struct hfi_cmd_sys_get_property_packet *pkt)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "%s invalid param :%p\n", __func__, pkt);
+ return -EINVAL;
+ }
+ pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet);
+ pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION;
+ return 0;
+}
+
+static struct hfi_packetization_ops hfi_default = {
+ .sys_init = create_pkt_cmd_sys_init,
+ .sys_pc_prep = create_pkt_cmd_sys_pc_prep,
+ .sys_idle_indicator = create_pkt_cmd_sys_idle_indicator,
+ .sys_power_control = create_pkt_cmd_sys_power_control,
+ .sys_set_resource = create_pkt_cmd_sys_set_resource,
+ .sys_debug_config = create_pkt_cmd_sys_debug_config,
+ .sys_coverage_config = create_pkt_cmd_sys_coverage_config,
+ .sys_release_resource = create_pkt_cmd_sys_release_resource,
+ .sys_ping = create_pkt_cmd_sys_ping,
+ .sys_image_version = create_pkt_cmd_sys_image_version,
+ .ssr_cmd = create_pkt_ssr_cmd,
+ .session_init = create_pkt_cmd_sys_session_init,
+ .session_cmd = create_pkt_cmd_session_cmd,
+ .session_set_buffers = create_pkt_cmd_session_set_buffers,
+ .session_release_buffers = create_pkt_cmd_session_release_buffers,
+ .session_etb_decoder = create_pkt_cmd_session_etb_decoder,
+ .session_etb_encoder = create_pkt_cmd_session_etb_encoder,
+ .session_ftb = create_pkt_cmd_session_ftb,
+ .session_parse_seq_header = create_pkt_cmd_session_parse_seq_header,
+ .session_get_seq_hdr = create_pkt_cmd_session_get_seq_hdr,
+ .session_get_buf_req = create_pkt_cmd_session_get_buf_req,
+ .session_flush = create_pkt_cmd_session_flush,
+ .session_get_property = create_pkt_cmd_session_get_property,
+ .session_set_property = create_pkt_cmd_session_set_property,
+};
+
+struct hfi_packetization_ops *get_venus_3_x_ops(void)
+{
+ static struct hfi_packetization_ops hfi_venus_3_x;
+
+ hfi_venus_3_x = hfi_default;
+
+ /* Override new HFI functions for HFI_PACKETIZATION_3XX here. */
+
+ return &hfi_venus_3_x;
+}
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+ enum hfi_packetization_type type)
+{
+ dprintk(VIDC_DBG, "%s selected\n",
+ type == HFI_PACKETIZATION_LEGACY ? "legacy packetization" :
+ type == HFI_PACKETIZATION_3XX ? "3xx packetization" :
+ "Unknown hfi");
+
+ switch (type) {
+ case HFI_PACKETIZATION_LEGACY:
+ return &hfi_default;
+ case HFI_PACKETIZATION_3XX:
+ return get_venus_3_x_ops();
+ }
+
+ return NULL;
+}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi_packetization.h
new file mode 100644
index 000000000000..020cc046d904
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.h
@@ -0,0 +1,99 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+#ifndef __HFI_PACKETIZATION__
+#define __HFI_PACKETIZATION__
+
+#include <linux/types.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi.h"
+#include "vidc_hfi_api.h"
+
+#define call_hfi_pkt_op(q, op, args...) \
+ (((q) && (q)->pkt_ops && (q)->pkt_ops->op) ? \
+ ((q)->pkt_ops->op(args)) : 0)
+
+enum hfi_packetization_type {
+ HFI_PACKETIZATION_LEGACY,
+ HFI_PACKETIZATION_3XX,
+};
+
+struct hfi_packetization_ops {
+ int (*sys_init)(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type);
+ int (*sys_pc_prep)(struct hfi_cmd_sys_pc_prep_packet *pkt);
+ int (*sys_idle_indicator)(struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 enable);
+ int (*sys_power_control)(struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 enable);
+ int (*sys_set_resource)(
+ struct hfi_cmd_sys_set_resource_packet *pkt,
+ struct vidc_resource_hdr *resource_hdr,
+ void *resource_value);
+ int (*sys_debug_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode);
+ int (*sys_coverage_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode);
+ int (*sys_release_resource)(
+ struct hfi_cmd_sys_release_resource_packet *pkt,
+ struct vidc_resource_hdr *resource_hdr);
+ int (*sys_ping)(struct hfi_cmd_sys_ping_packet *pkt);
+ int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt);
+ int (*ssr_cmd)(enum hal_ssr_trigger_type type,
+ struct hfi_cmd_sys_test_ssr_packet *pkt);
+ int (*session_init)(
+ struct hfi_cmd_sys_session_init_packet *pkt,
+ struct hal_session *session,
+ u32 session_domain, u32 session_codec);
+ int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt,
+ int pkt_type, struct hal_session *session);
+ int (*session_set_buffers)(
+ struct hfi_cmd_session_set_buffers_packet *pkt,
+ struct hal_session *session,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_release_buffers)(
+ struct hfi_cmd_session_release_buffer_packet *pkt,
+ struct hal_session *session,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_etb_decoder)(
+ struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+ struct hal_session *session,
+ struct vidc_frame_data *input_frame);
+ int (*session_etb_encoder)(
+ struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ *pkt, struct hal_session *session,
+ struct vidc_frame_data *input_frame);
+ int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt,
+ struct hal_session *session,
+ struct vidc_frame_data *output_frame);
+ int (*session_parse_seq_header)(
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+ struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_seq_hdr)(
+ struct hfi_cmd_session_get_sequence_header_packet *pkt,
+ struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_buf_req)(
+ struct hfi_cmd_session_get_property_packet *pkt,
+ struct hal_session *session);
+ int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt,
+ struct hal_session *session, enum hal_flush flush_mode);
+ int (*session_get_property)(
+ struct hfi_cmd_session_get_property_packet *pkt,
+ struct hal_session *session, enum hal_property ptype);
+ int (*session_set_property)(
+ struct hfi_cmd_session_set_property_packet *pkt,
+ struct hal_session *session,
+ enum hal_property ptype, void *pdata);
+};
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+ enum hfi_packetization_type);
+#endif
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
new file mode 100644
index 000000000000..a3dabd87773e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -0,0 +1,1475 @@
+/* Copyright (c) 2012-2015, 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/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/hash.h>
+#include <soc/qcom/smem.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_io.h"
+#include "msm_vidc_debug.h"
+#include "vidc_hfi.h"
+
+static enum vidc_status hfi_map_err_status(u32 hfi_err)
+{
+ enum vidc_status vidc_err;
+ switch (hfi_err) {
+ case HFI_ERR_NONE:
+ case HFI_ERR_SESSION_SAME_STATE_OPERATION:
+ vidc_err = VIDC_ERR_NONE;
+ break;
+ case HFI_ERR_SYS_FATAL:
+ vidc_err = VIDC_ERR_HW_FATAL;
+ break;
+ case HFI_ERR_SYS_VERSION_MISMATCH:
+ case HFI_ERR_SYS_INVALID_PARAMETER:
+ case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE:
+ case HFI_ERR_SESSION_INVALID_PARAMETER:
+ case HFI_ERR_SESSION_INVALID_SESSION_ID:
+ case HFI_ERR_SESSION_INVALID_STREAM_ID:
+ vidc_err = VIDC_ERR_BAD_PARAM;
+ break;
+ case HFI_ERR_SYS_INSUFFICIENT_RESOURCES:
+ case HFI_ERR_SYS_UNSUPPORTED_DOMAIN:
+ case HFI_ERR_SYS_UNSUPPORTED_CODEC:
+ case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY:
+ case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+ case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES:
+ case HFI_ERR_SESSION_UNSUPPORTED_STREAM:
+ vidc_err = VIDC_ERR_NOT_SUPPORTED;
+ break;
+ case HFI_ERR_SYS_MAX_SESSIONS_REACHED:
+ vidc_err = VIDC_ERR_MAX_CLIENTS;
+ break;
+ case HFI_ERR_SYS_SESSION_IN_USE:
+ vidc_err = VIDC_ERR_CLIENT_PRESENT;
+ break;
+ case HFI_ERR_SESSION_FATAL:
+ vidc_err = VIDC_ERR_CLIENT_FATAL;
+ break;
+ case HFI_ERR_SESSION_BAD_POINTER:
+ vidc_err = VIDC_ERR_BAD_PARAM;
+ break;
+ case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION:
+ vidc_err = VIDC_ERR_BAD_STATE;
+ break;
+ case HFI_ERR_SESSION_STREAM_CORRUPT:
+ case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED:
+ vidc_err = VIDC_ERR_BITSTREAM_ERR;
+ break;
+ case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED:
+ vidc_err = VIDC_ERR_IFRAME_EXPECTED;
+ break;
+ case HFI_ERR_SESSION_START_CODE_NOT_FOUND:
+ vidc_err = VIDC_ERR_START_CODE_NOT_FOUND;
+ break;
+ case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING:
+ default:
+ vidc_err = VIDC_ERR_FAIL;
+ break;
+ }
+ return vidc_err;
+}
+
+struct hal_session *hfi_process_get_session(
+ struct list_head *sessions, u32 session_id)
+{
+ struct hal_session *session = NULL;
+ bool found_session = false;
+
+ list_for_each_entry(session, sessions, list) {
+ if (hash32_ptr(session) == session_id) {
+ found_session = true;
+ break;
+ }
+ }
+ return found_session ? session : NULL;
+}
+
+static void hfi_process_sess_evt_seq_changed(
+ msm_vidc_callback callback, u32 device_id,
+ struct hal_session *session,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct msm_vidc_cb_event event_notify = {0};
+ int num_properties_changed;
+ struct hfi_frame_size *frame_sz;
+ struct hfi_profile_level *profile_level;
+ u8 *data_ptr;
+ int prop_id;
+
+ if (sizeof(struct hfi_msg_event_notify_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_init_done: bad_pkt_size\n");
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.size = sizeof(struct msm_vidc_cb_event);
+ num_properties_changed = pkt->event_data2;
+ switch (pkt->event_data1) {
+ case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES:
+ event_notify.hal_event_type =
+ HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES;
+ break;
+ case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES:
+ event_notify.hal_event_type =
+ HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES;
+ break;
+ default:
+ break;
+ }
+ if (num_properties_changed) {
+ data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+ do {
+ prop_id = (int) *((u32 *)data_ptr);
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_FRAME_SIZE:
+ data_ptr = data_ptr + sizeof(u32);
+ frame_sz =
+ (struct hfi_frame_size *) data_ptr;
+ event_notify.width = frame_sz->width;
+ event_notify.height = frame_sz->height;
+ dprintk(VIDC_DBG, "height: %d width: %d\n",
+ frame_sz->height, frame_sz->width);
+ data_ptr +=
+ sizeof(struct hfi_frame_size);
+ break;
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+ data_ptr = data_ptr + sizeof(u32);
+ profile_level =
+ (struct hfi_profile_level *) data_ptr;
+ dprintk(VIDC_DBG, "profile: %d level: %d\n",
+ profile_level->profile,
+ profile_level->level);
+ data_ptr +=
+ sizeof(struct hfi_profile_level);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "%s cmd: %#x not supported\n",
+ __func__, prop_id);
+ break;
+ }
+ num_properties_changed--;
+ } while (num_properties_changed > 0);
+ }
+ cmd_done.data = &event_notify;
+ callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
+static void hfi_process_evt_release_buffer_ref(
+ msm_vidc_callback callback, u32 device_id,
+ struct hal_session *session,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct msm_vidc_cb_event event_notify = {0};
+
+ struct hfi_msg_release_buffer_ref_event_packet *data;
+
+ dprintk(VIDC_DBG,
+ "RECEIVED: EVENT_NOTIFY - release_buffer_reference\n");
+ if (sizeof(struct hfi_msg_event_notify_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_init_done: bad_pkt_size\n");
+ return;
+ }
+
+ data = (struct hfi_msg_release_buffer_ref_event_packet *)
+ pkt->rg_ext_event_data;
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.size = sizeof(struct msm_vidc_cb_event);
+
+ event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+ event_notify.packet_buffer = data->packet_buffer;
+ event_notify.extra_data_buffer = data->extra_data_buffer;
+ cmd_done.data = &event_notify;
+ callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
+static void hfi_process_sys_error(
+ msm_vidc_callback callback, u32 device_id)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ cmd_done.device_id = device_id;
+ callback(SYS_ERROR, &cmd_done);
+}
+static void hfi_process_session_error(
+ msm_vidc_callback callback, u32 device_id,
+ struct hal_session *session,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->event_data1);
+ dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
+ pkt->event_data1);
+ switch (pkt->event_data1) {
+ case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
+ case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
+ case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+ case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
+ cmd_done.status = VIDC_ERR_NONE;
+ dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
+ break;
+ default:
+ dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+ callback(SESSION_ERROR, &cmd_done);
+ break;
+ }
+}
+static void hfi_process_event_notify(msm_vidc_callback callback, u32 device_id,
+ struct hal_session *session,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n");
+
+ if (!callback || !pkt ||
+ pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return;
+ }
+
+ switch (pkt->event_id) {
+ case HFI_EVENT_SYS_ERROR:
+ dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n",
+ pkt->event_data1, pkt->event_data2);
+ hfi_process_sys_error(callback, device_id);
+ break;
+ case HFI_EVENT_SESSION_PROPERTY_CHANGED:
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED[%p]\n",
+ session);
+ break;
+ }
+
+ if (!session) {
+ dprintk(VIDC_ERR, "%s Got invalid session id\n", __func__);
+ return;
+ }
+
+ switch (pkt->event_id) {
+ case HFI_EVENT_SESSION_ERROR:
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR[%p]\n", session);
+ hfi_process_session_error(callback, device_id, session, pkt);
+ break;
+ case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%p]\n",
+ session);
+ hfi_process_sess_evt_seq_changed(callback, device_id,
+ session, pkt);
+ break;
+ case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+ dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%p]\n",
+ session);
+ hfi_process_evt_release_buffer_ref(callback, device_id,
+ session, pkt);
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "hal_process_event_notify: unknown_event_id[%p]\n",
+ session);
+ break;
+ }
+}
+static void hfi_process_sys_init_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_init_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct vidc_hal_sys_init_done sys_init_done = {0};
+ u32 rem_bytes, bytes_read = 0, num_properties;
+ u8 *data_ptr;
+ int prop_id;
+ enum vidc_status status = VIDC_ERR_NONE;
+
+ dprintk(VIDC_DBG, "RECEIVED: SYS_INIT_DONE\n");
+ if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_sys_init_done: bad_pkt_size: %d\n",
+ pkt->size);
+ return;
+ }
+
+ status = hfi_map_err_status(pkt->error_type);
+
+ if (!status) {
+ if (!pkt->num_properties) {
+ dprintk(VIDC_ERR,
+ "hal_process_sys_init_done: no_properties\n");
+ status = VIDC_ERR_FAIL;
+ goto err_no_prop;
+ }
+
+ rem_bytes = pkt->size - sizeof(struct
+ hfi_msg_sys_init_done_packet) + sizeof(u32);
+
+ if (!rem_bytes) {
+ dprintk(VIDC_ERR,
+ "hal_process_sys_init_done: missing_prop_info\n");
+ status = VIDC_ERR_FAIL;
+ goto err_no_prop;
+ }
+
+ data_ptr = (u8 *) &pkt->rg_property_data[0];
+ num_properties = pkt->num_properties;
+
+ while (num_properties && rem_bytes >= sizeof(u32)) {
+ prop_id = *((u32 *)data_ptr);
+ data_ptr = data_ptr + 4;
+
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
+ {
+ struct hfi_codec_supported *prop =
+ (struct hfi_codec_supported *) data_ptr;
+ if (rem_bytes < sizeof(struct
+ hfi_codec_supported)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ sys_init_done.dec_codec_supported =
+ prop->decoder_codec_supported;
+ sys_init_done.enc_codec_supported =
+ prop->encoder_codec_supported;
+ break;
+ }
+ default:
+ dprintk(VIDC_ERR,
+ "hal_process_sys_init_done: bad_prop_id\n");
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ if (!status) {
+ rem_bytes -= bytes_read;
+ data_ptr += bytes_read;
+ num_properties--;
+ }
+ }
+ }
+err_no_prop:
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = NULL;
+ cmd_done.status = (u32) status;
+ cmd_done.size = sizeof(struct vidc_hal_sys_init_done);
+ cmd_done.data = (void *) &sys_init_done;
+ callback(SYS_INIT_DONE, &cmd_done);
+}
+
+static void hfi_process_sys_rel_resource_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_release_resource_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ enum vidc_status status = VIDC_ERR_NONE;
+ u32 pkt_size;
+ dprintk(VIDC_DBG, "RECEIVED: SYS_RELEASE_RESOURCE_DONE\n");
+ pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
+ if (pkt_size > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_sys_rel_resource_done: bad size: %d\n",
+ pkt->size);
+ return;
+ }
+ status = hfi_map_err_status(pkt->error_type);
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = NULL;
+ cmd_done.status = (u32) status;
+ cmd_done.size = 0;
+ cmd_done.data = NULL;
+ callback(RELEASE_RESOURCE_DONE, &cmd_done);
+}
+
+static inline void copy_cap_prop(
+ struct hfi_capability_supported *in,
+ struct vidc_hal_session_init_done *sess_init_done)
+{
+ struct hal_capability_supported *out = NULL;
+ if (!in || !sess_init_done) {
+ dprintk(VIDC_ERR, "%s Invalid input parameter\n",
+ __func__);
+ return;
+ }
+ switch (in->capability_type) {
+ case HFI_CAPABILITY_FRAME_WIDTH:
+ out = &sess_init_done->width;
+ break;
+
+ case HFI_CAPABILITY_FRAME_HEIGHT:
+ out = &sess_init_done->height;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_FRAME:
+ out = &sess_init_done->mbs_per_frame;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_SECOND:
+ out = &sess_init_done->mbs_per_sec;
+ break;
+
+ case HFI_CAPABILITY_FRAMERATE:
+ out = &sess_init_done->frame_rate;
+ break;
+
+ case HFI_CAPABILITY_SCALE_X:
+ out = &sess_init_done->scale_x;
+ break;
+
+ case HFI_CAPABILITY_SCALE_Y:
+ out = &sess_init_done->scale_y;
+ break;
+
+ case HFI_CAPABILITY_BITRATE:
+ out = &sess_init_done->bitrate;
+ break;
+
+ case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+ out = &sess_init_done->hier_p;
+ break;
+
+ case HFI_CAPABILITY_ENC_LTR_COUNT:
+ out = &sess_init_done->ltr_count;
+ break;
+
+ case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
+ out = &sess_init_done->secure_output2_threshold;
+ break;
+ }
+
+ if (out) {
+ out->min = in->min;
+ out->max = in->max;
+ out->step_size = in->step_size;
+ }
+}
+
+enum vidc_status hfi_process_sess_init_done_prop_read(
+ struct hfi_msg_sys_session_init_done_packet *pkt,
+ struct vidc_hal_session_init_done *sess_init_done)
+{
+ u32 rem_bytes, num_properties;
+ u8 *data_ptr;
+ enum vidc_status status = VIDC_ERR_NONE;
+ u32 prop_id, next_offset = 0;
+ u32 prop_count = 0;
+
+ rem_bytes = pkt->size - sizeof(struct
+ hfi_msg_sys_session_init_done_packet) + sizeof(u32);
+
+ if (!rem_bytes) {
+ dprintk(VIDC_ERR,
+ "hfi_msg_sys_session_init_done: missing_prop_info\n");
+ return VIDC_ERR_FAIL;
+ }
+
+ status = hfi_map_err_status(pkt->error_type);
+ if (status)
+ return status;
+
+ data_ptr = (u8 *) &pkt->rg_property_data[0];
+ num_properties = pkt->num_properties;
+
+ while (status == VIDC_ERR_NONE && num_properties &&
+ rem_bytes >= sizeof(u32)) {
+ prop_id = *((u32 *)data_ptr);
+ next_offset = sizeof(u32);
+
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+ {
+ struct hfi_capability_supported_info *prop =
+ (struct hfi_capability_supported_info *)
+ (data_ptr + next_offset);
+ u32 num_capabilities;
+ struct hfi_capability_supported *cap_ptr;
+
+ if ((rem_bytes - next_offset) < sizeof(*cap_ptr)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+
+ num_capabilities = prop->num_capabilities;
+ cap_ptr = &prop->rg_data[0];
+ next_offset += sizeof(u32);
+
+ while (num_capabilities &&
+ (rem_bytes - next_offset) >= sizeof(u32)) {
+ copy_cap_prop(cap_ptr, sess_init_done);
+ cap_ptr++;
+ next_offset += sizeof(*cap_ptr);
+ num_capabilities--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ {
+ struct hfi_uncompressed_format_supported *prop =
+ (struct hfi_uncompressed_format_supported *)
+ (data_ptr + next_offset);
+
+ u32 num_format_entries;
+ char *fmt_ptr;
+ struct hfi_uncompressed_plane_info *plane_info;
+
+ if ((rem_bytes - next_offset) < sizeof(*prop)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ num_format_entries = prop->format_entries;
+ next_offset = sizeof(*prop) - sizeof(u32);
+ fmt_ptr = (char *)&prop->rg_format_info[0];
+
+ while (num_format_entries) {
+ u32 bytes_to_skip;
+ plane_info =
+ (struct hfi_uncompressed_plane_info *) fmt_ptr;
+
+ if ((rem_bytes - next_offset) <
+ sizeof(*plane_info)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ bytes_to_skip = sizeof(*plane_info) -
+ sizeof(struct
+ hfi_uncompressed_plane_constraints) +
+ plane_info->num_planes *
+ sizeof(struct
+ hfi_uncompressed_plane_constraints);
+
+ fmt_ptr += bytes_to_skip;
+ next_offset += bytes_to_skip;
+ num_format_entries--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED:
+ {
+ struct hfi_properties_supported *prop =
+ (struct hfi_properties_supported *)
+ (data_ptr + next_offset);
+
+ next_offset += sizeof(*prop) - sizeof(u32)
+ + prop->num_properties * sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+ {
+ char *ptr = NULL;
+ int count = 0;
+ struct hfi_profile_level *prop_level;
+ struct hfi_profile_level_supported *prop =
+ (struct hfi_profile_level_supported *)
+ (data_ptr + next_offset);
+ ptr = (char *) &prop->rg_profile_level[0];
+ dprintk(VIDC_DBG, "prop->profile_count: %d\n",
+ prop->profile_count);
+ prop_count = prop->profile_count;
+ if (prop_count > MAX_PROFILE_COUNT) {
+ prop_count = MAX_PROFILE_COUNT;
+ dprintk(VIDC_WARN,
+ "prop count exceeds max profile count\n");
+ }
+ while (prop_count) {
+ ptr++;
+ prop_level = (struct hfi_profile_level *) ptr;
+ sess_init_done->
+ profile_level.profile_level[count].profile
+ = prop_level->profile;
+ sess_init_done->
+ profile_level.profile_level[count].level
+ = prop_level->level;
+ prop_count--;
+ count++;
+ ptr +=
+ sizeof(struct hfi_profile_level) / sizeof(u32);
+ }
+ next_offset += sizeof(*prop) -
+ sizeof(struct hfi_profile_level) +
+ prop->profile_count *
+ sizeof(struct hfi_profile_level);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ {
+ next_offset +=
+ sizeof(struct hfi_nal_stream_format_supported);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH:
+ {
+ next_offset +=
+ sizeof(struct hfi_intra_refresh);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
+ {
+ struct hfi_buffer_alloc_mode_supported *prop =
+ (struct hfi_buffer_alloc_mode_supported *)
+ (data_ptr + next_offset);
+ int i;
+ if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
+ prop->buffer_type == HFI_BUFFER_OUTPUT2) {
+ sess_init_done->alloc_mode_out = 0;
+ for (i = 0; i < prop->num_entries; i++) {
+ switch (prop->rg_data[i]) {
+ case HFI_BUFFER_MODE_STATIC:
+ sess_init_done->alloc_mode_out
+ |= HAL_BUFFER_MODE_STATIC;
+ break;
+ case HFI_BUFFER_MODE_DYNAMIC:
+ sess_init_done->alloc_mode_out
+ |= HAL_BUFFER_MODE_DYNAMIC;
+ break;
+ }
+ if (i >= 32) {
+ dprintk(VIDC_ERR,
+ "%s - num_entries: %d from f/w seems suspect\n",
+ __func__, prop->num_entries);
+ break;
+ }
+ }
+ }
+ next_offset += sizeof(*prop) -
+ sizeof(u32) + prop->num_entries * sizeof(u32);
+ num_properties--;
+ break;
+ }
+ default:
+ dprintk(VIDC_DBG,
+ "%s default case - %#x\n", __func__, prop_id);
+ }
+ rem_bytes -= next_offset;
+ data_ptr += next_offset;
+ }
+ return status;
+}
+
+static void hfi_process_sess_get_prop_profile_level(
+ struct hfi_msg_session_property_info_packet *prop,
+ struct hfi_profile_level *profile_level)
+{
+ struct hfi_profile_level *hfi_profile_level;
+ u32 req_bytes;
+ dprintk(VIDC_DBG, "Entered %s\n", __func__);
+ if (!prop) {
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_profile_level: bad_prop: %p\n",
+ prop);
+ return;
+ }
+ req_bytes = prop->size - sizeof(
+ struct hfi_msg_session_property_info_packet);
+
+ if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) {
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_profile_level: bad_pkt: %d\n",
+ req_bytes);
+ return;
+ }
+ hfi_profile_level = (struct hfi_profile_level *)
+ &prop->rg_property_data[1];
+ profile_level->profile = hfi_profile_level->profile;
+ profile_level->level = hfi_profile_level->level;
+ dprintk(VIDC_DBG, "%s profile: %d level: %d\n",
+ __func__, profile_level->profile,
+ profile_level->level);
+}
+
+static void hfi_process_sess_get_prop_buf_req(
+ struct hfi_msg_session_property_info_packet *prop,
+ struct buffer_requirements *buffreq)
+{
+ struct hfi_buffer_requirements *hfi_buf_req;
+ u32 req_bytes;
+
+ if (!prop) {
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_prop_buf_req: bad_prop: %p\n",
+ prop);
+ return;
+ }
+ req_bytes = prop->size - sizeof(
+ struct hfi_msg_session_property_info_packet);
+
+ if (!req_bytes || req_bytes % sizeof(struct hfi_buffer_requirements) ||
+ !prop->rg_property_data[1]) {
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_prop_buf_req: bad_pkt: %d\n",
+ req_bytes);
+ return;
+ }
+
+ hfi_buf_req = (struct hfi_buffer_requirements *)
+ &prop->rg_property_data[1];
+
+ if (!hfi_buf_req) {
+ dprintk(VIDC_ERR, "%s - invalid buffer req pointer\n",
+ __func__);
+ return;
+ }
+
+ while (req_bytes) {
+ if (hfi_buf_req->buffer_size &&
+ hfi_buf_req->buffer_count_min > hfi_buf_req->
+ buffer_count_actual)
+ dprintk(VIDC_WARN,
+ "hal_process_sess_get_prop_buf_req:"
+ "bad_buf_req\n");
+
+ dprintk(VIDC_DBG, "got buffer requirements for: %d\n",
+ hfi_buf_req->buffer_type);
+ switch (hfi_buf_req->buffer_type) {
+ case HFI_BUFFER_INPUT:
+ memcpy(&buffreq->buffer[0], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT;
+ break;
+ case HFI_BUFFER_OUTPUT:
+ memcpy(&buffreq->buffer[1], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT;
+ break;
+ case HFI_BUFFER_OUTPUT2:
+ memcpy(&buffreq->buffer[2], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2;
+ break;
+ case HFI_BUFFER_EXTRADATA_INPUT:
+ memcpy(&buffreq->buffer[3], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[3].buffer_type =
+ HAL_BUFFER_EXTRADATA_INPUT;
+ break;
+ case HFI_BUFFER_EXTRADATA_OUTPUT:
+ memcpy(&buffreq->buffer[4], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[4].buffer_type =
+ HAL_BUFFER_EXTRADATA_OUTPUT;
+ break;
+ case HFI_BUFFER_EXTRADATA_OUTPUT2:
+ memcpy(&buffreq->buffer[5], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[5].buffer_type =
+ HAL_BUFFER_EXTRADATA_OUTPUT2;
+ break;
+ case HFI_BUFFER_INTERNAL_SCRATCH:
+ memcpy(&buffreq->buffer[6], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[6].buffer_type =
+ HAL_BUFFER_INTERNAL_SCRATCH;
+ break;
+ case HFI_BUFFER_INTERNAL_SCRATCH_1:
+ memcpy(&buffreq->buffer[7], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[7].buffer_type =
+ HAL_BUFFER_INTERNAL_SCRATCH_1;
+ break;
+ case HFI_BUFFER_INTERNAL_SCRATCH_2:
+ memcpy(&buffreq->buffer[8], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[8].buffer_type =
+ HAL_BUFFER_INTERNAL_SCRATCH_2;
+ break;
+ case HFI_BUFFER_INTERNAL_PERSIST:
+ memcpy(&buffreq->buffer[9], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[9].buffer_type =
+ HAL_BUFFER_INTERNAL_PERSIST;
+ break;
+ case HFI_BUFFER_INTERNAL_PERSIST_1:
+ memcpy(&buffreq->buffer[10], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[10].buffer_type =
+ HAL_BUFFER_INTERNAL_PERSIST_1;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
+ hfi_buf_req->buffer_type);
+ break;
+ }
+ req_bytes -= sizeof(struct hfi_buffer_requirements);
+ hfi_buf_req++;
+ }
+}
+
+static void hfi_process_session_prop_info(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_property_info_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct hfi_profile_level profile_level = {0};
+ struct buffer_requirements buff_req;
+
+ memset(&buff_req, 0, sizeof(struct buffer_requirements));
+ dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%p]\n", session);
+
+ if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_prop_info: bad_pkt_size\n");
+ return;
+ }
+
+ if (!pkt->num_properties) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_prop_info: no_properties\n");
+ return;
+ }
+
+ switch (pkt->rg_property_data[0]) {
+ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+ hfi_process_sess_get_prop_buf_req(pkt, &buff_req);
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.data = &buff_req;
+ cmd_done.size = sizeof(struct buffer_requirements);
+ callback(SESSION_PROPERTY_INFO, &cmd_done);
+ break;
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+ hfi_process_sess_get_prop_profile_level(pkt, &profile_level);
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.data = &profile_level;
+ cmd_done.size = sizeof(struct hal_profile_level);
+ callback(SESSION_PROPERTY_INFO, &cmd_done);
+ break;
+ default:
+ dprintk(VIDC_DBG,
+ "hal_process_session_prop_info: unknown_prop_id: %x\n",
+ pkt->rg_property_data[0]);
+ break;
+ }
+}
+
+static void hfi_process_session_init_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hal_session *session,
+ struct hfi_msg_sys_session_init_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct vidc_hal_session_init_done session_init_done;
+
+ if (!session) {
+ dprintk(VIDC_ERR, "%s - invalid session\n", __func__);
+ return;
+ }
+
+ memset(&session_init_done, 0, sizeof(struct
+ vidc_hal_session_init_done));
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%p]\n", session);
+
+ if (sizeof(struct hfi_msg_sys_session_init_done_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_init_done: bad_pkt_size\n");
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = &session_init_done;
+ if (!cmd_done.status) {
+ cmd_done.status = hfi_process_sess_init_done_prop_read(
+ pkt, &session_init_done);
+ } else {
+ dprintk(VIDC_WARN,
+ "Sess init failed: %p, %p\n",
+ session->session_id, session);
+ }
+ cmd_done.size = sizeof(struct vidc_hal_session_init_done);
+ callback(SESSION_INIT_DONE, &cmd_done);
+}
+
+static void hfi_process_session_load_res_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_load_resources_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%p]\n",
+ session);
+
+ if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
+ pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_load_res_done: bad packet size: %d\n",
+ pkt->size);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ callback(SESSION_LOAD_RESOURCE_DONE, &cmd_done);
+}
+
+static void hfi_process_session_flush_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_flush_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%p]\n", session);
+
+ if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_flush_done: bad packet size: %d\n",
+ pkt->size);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = (void *)(unsigned long)pkt->flush_type;
+ cmd_done.size = sizeof(u32);
+ callback(SESSION_FLUSH_DONE, &cmd_done);
+}
+
+static void hfi_process_session_etb_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_empty_buffer_done_packet *pkt)
+{
+ struct msm_vidc_cb_data_done data_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%p]\n", session);
+
+ if (!pkt || pkt->size <
+ sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_etb_done: bad_pkt_size\n");
+ return;
+ }
+
+ data_done.device_id = device_id;
+ data_done.session_id = session->session_id;
+ data_done.status = hfi_map_err_status(pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = pkt->input_tag;
+ data_done.input_done.offset = pkt->offset;
+ data_done.input_done.filled_len = pkt->filled_len;
+ data_done.input_done.packet_buffer =
+ (ion_phys_addr_t)pkt->packet_buffer;
+ data_done.input_done.extra_data_buffer =
+ (ion_phys_addr_t)pkt->extra_data_buffer;
+ data_done.input_done.status =
+ hfi_map_err_status(pkt->error_type);
+
+ trace_msm_v4l2_vidc_buffer_event_end("ETB",
+ (u32)pkt->packet_buffer, -1, -1,
+ pkt->filled_len, pkt->offset);
+ callback(SESSION_ETB_DONE, &data_done);
+}
+
+static void hfi_process_session_ftb_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ void *msg_hdr)
+{
+ struct msm_vidc_cb_data_done data_done = {0};
+ bool is_decoder = session->is_decoder;
+
+ if (!msg_hdr) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return;
+ }
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%p]\n", session);
+
+ if (!is_decoder) {
+ struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt =
+ (struct hfi_msg_session_fill_buffer_done_compressed_packet *)
+ msg_hdr;
+ if (sizeof(struct
+ hfi_msg_session_fill_buffer_done_compressed_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_ftb_done: bad_pkt_size\n");
+ return;
+ } else if (pkt->error_type != HFI_ERR_NONE) {
+ dprintk(VIDC_ERR,
+ "got buffer back with error %x\n",
+ pkt->error_type);
+ /* Proceed with the FBD */
+ }
+
+ data_done.device_id = device_id;
+ data_done.session_id = session->session_id;
+ data_done.status = hfi_map_err_status(pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = 0;
+
+ data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+ data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+ data_done.output_done.flags1 = pkt->flags;
+ data_done.output_done.mark_target = pkt->mark_target;
+ data_done.output_done.mark_data = pkt->mark_data;
+ data_done.output_done.stats = pkt->stats;
+ data_done.output_done.offset1 = pkt->offset;
+ data_done.output_done.alloc_len1 = pkt->alloc_len;
+ data_done.output_done.filled_len1 = pkt->filled_len;
+ data_done.output_done.picture_type = pkt->picture_type;
+ data_done.output_done.packet_buffer1 =
+ (ion_phys_addr_t)pkt->packet_buffer;
+ data_done.output_done.extra_data_buffer =
+ (ion_phys_addr_t)pkt->extra_data_buffer;
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+ } else /* if (is_decoder) */ {
+ struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
+ (struct hfi_msg_session_fbd_uncompressed_plane0_packet *)
+ msg_hdr;
+ if (sizeof(
+ struct hfi_msg_session_fbd_uncompressed_plane0_packet) >
+ pkt->size) {
+ dprintk(VIDC_ERR,
+ "hal_process_session_ftb_done: bad_pkt_size\n");
+ return;
+ }
+
+ data_done.device_id = device_id;
+ data_done.session_id = session->session_id;
+ data_done.status = hfi_map_err_status(pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = 0;
+
+ data_done.output_done.stream_id = pkt->stream_id;
+ data_done.output_done.view_id = pkt->view_id;
+ data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+ data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+ data_done.output_done.flags1 = pkt->flags;
+ data_done.output_done.mark_target = pkt->mark_target;
+ data_done.output_done.mark_data = pkt->mark_data;
+ data_done.output_done.stats = pkt->stats;
+ data_done.output_done.alloc_len1 = pkt->alloc_len;
+ data_done.output_done.filled_len1 = pkt->filled_len;
+ data_done.output_done.offset1 = pkt->offset;
+ data_done.output_done.frame_width = pkt->frame_width;
+ data_done.output_done.frame_height = pkt->frame_height;
+ data_done.output_done.start_x_coord = pkt->start_x_coord;
+ data_done.output_done.start_y_coord = pkt->start_y_coord;
+ data_done.output_done.input_tag1 = pkt->input_tag;
+ data_done.output_done.picture_type = pkt->picture_type;
+ data_done.output_done.packet_buffer1 = pkt->packet_buffer;
+ data_done.output_done.extra_data_buffer =
+ pkt->extra_data_buffer;
+
+ if (!pkt->stream_id)
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+ else if (pkt->stream_id == 1)
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2;
+ }
+
+ trace_msm_v4l2_vidc_buffer_event_end("FTB",
+ (u32)data_done.output_done.packet_buffer1,
+ (((u64)data_done.output_done.timestamp_hi) << 32)
+ + ((u64)data_done.output_done.timestamp_lo),
+ data_done.output_done.alloc_len1,
+ data_done.output_done.filled_len1,
+ data_done.output_done.offset1);
+
+ callback(SESSION_FTB_DONE, &data_done);
+}
+
+static void hfi_process_session_start_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_start_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%p]\n", session);
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_start_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+ __func__);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ callback(SESSION_START_DONE, &cmd_done);
+}
+
+static void hfi_process_session_stop_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_stop_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%p]\n", session);
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_stop_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+ __func__);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ callback(SESSION_STOP_DONE, &cmd_done);
+}
+
+static void hfi_process_session_rel_res_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_release_resources_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%p]\n",
+ session);
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_release_resources_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+ __func__);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
+}
+
+static void hfi_process_session_rel_buf_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_release_buffers_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ if (!pkt || pkt->size <
+ sizeof(struct
+ hfi_msg_session_release_buffers_done_packet)) {
+ dprintk(VIDC_ERR, "bad packet/packet size %d\n",
+ pkt ? pkt->size : 0);
+ return;
+ }
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%p]\n",
+ session);
+
+ cmd_done.device_id = device_id;
+ cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ if (pkt->rg_buffer_info) {
+ cmd_done.data = (void *) &pkt->rg_buffer_info;
+ cmd_done.size = sizeof(struct hfi_buffer_info);
+ } else {
+ dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+ }
+ callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
+}
+
+static void hfi_process_session_end_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_sys_session_end_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%p]\n", session);
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_sys_session_end_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n", __func__);
+ return;
+ }
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ callback(SESSION_END_DONE, &cmd_done);
+}
+
+static void hfi_process_session_abort_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_sys_session_abort_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+ dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%p]\n", session);
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size: %d\n",
+ __func__, pkt ? pkt->size : 0);
+ return;
+ }
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = session->session_id;
+ cmd_done.status = hfi_map_err_status(pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+
+ callback(SESSION_ABORT_DONE, &cmd_done);
+}
+
+static void hfi_process_session_get_seq_hdr_done(msm_vidc_callback callback,
+ u32 device_id, struct hal_session *session,
+ struct hfi_msg_session_get_sequence_header_done_packet *pkt)
+{
+ struct msm_vidc_cb_data_done data_done = {0};
+ if (!pkt || pkt->size !=
+ sizeof(struct
+ hfi_msg_session_get_sequence_header_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+ __func__);
+ return;
+ }
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_GET_SEQ_HDR_DONE[%p]\n", session);
+
+ data_done.device_id = device_id;
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.session_id = session->session_id;
+ data_done.status = hfi_map_err_status(pkt->error_type);
+ data_done.output_done.packet_buffer1 =
+ (ion_phys_addr_t)pkt->sequence_header;
+ data_done.output_done.filled_len1 = pkt->header_len;
+ dprintk(VIDC_INFO, "seq_hdr: %#x, Length: %d\n",
+ pkt->sequence_header, pkt->header_len);
+ callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
+}
+
+static void hfi_process_sys_get_prop_image_version(
+ struct hfi_msg_sys_property_info_packet *pkt)
+{
+ int i = 0;
+ u32 smem_block_size = 0;
+ u8 *smem_table_ptr;
+ char version[256];
+ const u32 version_string_size = 128;
+ const u32 smem_image_index_venus = 14 * 128;
+ u8 *str_image_version;
+ int req_bytes;
+
+ req_bytes = pkt->size - sizeof(*pkt);
+ if (req_bytes < version_string_size ||
+ !pkt->rg_property_data[1] ||
+ pkt->num_properties > 1) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_get_prop_image_version: bad_pkt: %d\n",
+ req_bytes);
+ return;
+ }
+ str_image_version = (u8 *)&pkt->rg_property_data[1];
+ /*
+ * The version string returned by firmware includes null
+ * characters at the start and in between. Replace the null
+ * characters with space, to print the version info.
+ */
+ for (i = 0; i < version_string_size; i++) {
+ if (str_image_version[i] != '\0')
+ version[i] = str_image_version[i];
+ else
+ version[i] = ' ';
+ }
+ version[i] = '\0';
+ dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+ smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+ &smem_block_size, 0, SMEM_ANY_HOST_FLAG);
+ if ((smem_image_index_venus + version_string_size) <= smem_block_size &&
+ smem_table_ptr)
+ memcpy(smem_table_ptr + smem_image_index_venus,
+ str_image_version, version_string_size);
+}
+
+static void hfi_process_sys_property_info(
+ struct hfi_msg_sys_property_info_packet *pkt)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+ return;
+ }
+ if (pkt->size < sizeof(*pkt)) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: bad_pkt_size\n");
+ return;
+ }
+ if (!pkt->num_properties) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: no_properties\n");
+ return;
+ }
+
+ switch (pkt->rg_property_data[0]) {
+ case HFI_PROPERTY_SYS_IMAGE_VERSION:
+ hfi_process_sys_get_prop_image_version(pkt);
+ break;
+ default:
+ dprintk(VIDC_DBG,
+ "hfi_process_sys_property_info: unknown_prop_id: %x\n",
+ pkt->rg_property_data[0]);
+ }
+}
+
+u32 hfi_process_msg_packet(msm_vidc_callback callback, u32 device_id,
+ struct vidc_hal_msg_pkt_hdr *msg_hdr,
+ struct list_head *sessions, struct mutex *session_lock)
+{
+ u32 rc = 0;
+ struct hal_session *session = NULL;
+ typedef void (*session_pkt_func_def)(msm_vidc_callback, u32,
+ void *, void *);
+ typedef void (*sys_pkt_func_def)(msm_vidc_callback, u32, void *);
+ session_pkt_func_def session_pkt_func = NULL;
+ sys_pkt_func_def sys_pkt_func = NULL;
+
+ if (!callback || !session_lock || !msg_hdr ||
+ msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+ __func__);
+ rc = -EINVAL;
+ return rc;
+ }
+
+ dprintk(VIDC_INFO, "Received: %#x\n", msg_hdr->packet);
+ rc = (u32) msg_hdr->packet;
+ switch (msg_hdr->packet) {
+ case HFI_MSG_EVENT_NOTIFY:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_event_notify;
+ break;
+ case HFI_MSG_SYS_INIT_DONE:
+ sys_pkt_func = (sys_pkt_func_def)hfi_process_sys_init_done;
+ break;
+ case HFI_MSG_SYS_SESSION_INIT_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_init_done;
+ break;
+ case HFI_MSG_SYS_PROPERTY_INFO:
+ sys_pkt_func = (sys_pkt_func_def)hfi_process_sys_property_info;
+ break;
+ case HFI_MSG_SYS_SESSION_END_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_end_done;
+ break;
+ case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_load_res_done;
+ break;
+ case HFI_MSG_SESSION_START_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_start_done;
+ break;
+ case HFI_MSG_SESSION_STOP_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_stop_done;
+ break;
+ case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_etb_done;
+ break;
+ case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_ftb_done;
+ break;
+ case HFI_MSG_SESSION_FLUSH_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_flush_done;
+ break;
+ case HFI_MSG_SESSION_PROPERTY_INFO:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_prop_info;
+ break;
+ case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_rel_res_done;
+ break;
+ case HFI_MSG_SYS_RELEASE_RESOURCE:
+ sys_pkt_func =
+ (sys_pkt_func_def)hfi_process_sys_rel_resource_done;
+ break;
+ case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)
+ hfi_process_session_get_seq_hdr_done;
+ break;
+ case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_rel_buf_done;
+ break;
+ case HFI_MSG_SYS_SESSION_ABORT_DONE:
+ session_pkt_func =
+ (session_pkt_func_def)hfi_process_session_abort_done;
+ break;
+ case HFI_MSG_SYS_PC_PREP_DONE:
+ break;
+ default:
+ dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d\n", msg_hdr->packet);
+ break;
+ }
+ mutex_lock(session_lock);
+ if (session_pkt_func) {
+ struct vidc_hal_session_cmd_pkt *pkt =
+ (struct vidc_hal_session_cmd_pkt *)msg_hdr;
+ session = hfi_process_get_session(sessions, pkt->session_id);
+ /* Event of type HFI_EVENT_SYS_ERROR will not have any session
+ * associated with it */
+ if (!session && msg_hdr->packet != HFI_MSG_EVENT_NOTIFY) {
+ dprintk(VIDC_ERR, "%s Got invalid session id: %d\n",
+ __func__, pkt->session_id);
+ goto invalid_session;
+ }
+ }
+
+ if (session_pkt_func)
+ session_pkt_func(callback, device_id, session, msg_hdr);
+ if (sys_pkt_func)
+ sys_pkt_func(callback, device_id, msg_hdr);
+
+invalid_session:
+ mutex_unlock(session_lock);
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
new file mode 100644
index 000000000000..ff9ff92283f3
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -0,0 +1,794 @@
+/* Copyright (c) 2012-2015, 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 <asm/dma-iommu.h>
+#include <linux/dma-attrs.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-direction.h>
+#include <linux/iommu.h>
+#include <linux/msm_iommu_domains.h>
+#ifdef CONFIG_ION
+#include <linux/msm_ion.h>
+#endif
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/msm_vidc.h>
+#include <media/videobuf2-dma-contig.h>
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+
+struct smem_client {
+ int mem_type;
+ void *clnt;
+ struct msm_vidc_platform_resources *res;
+};
+
+static int get_device_address(struct smem_client *smem_client,
+ struct dma_buf *buf, dma_addr_t *iova,
+ unsigned long *buffer_size,
+ unsigned long flags, struct context_bank_info *cb,
+ struct dma_mapping_info *mapping_info)
+{
+ int rc = 0;
+ struct dma_buf_attachment *attach;
+ struct sg_table *table = NULL;
+ phys_addr_t phys, orig_phys;
+
+ if (!iova || !buffer_size || !buf || !smem_client || !mapping_info || !cb) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p, %p\n",
+ smem_client, buf, iova, buffer_size, cb);
+ return -EINVAL;
+ }
+
+
+ /* Prepare a dma buf for dma on the given device */
+ attach = dma_buf_attach(buf, cb->dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ rc = PTR_ERR(attach) ?: -ENOMEM;
+ dprintk(VIDC_ERR, "Failed to attach dmabuf\n");
+ goto mem_buf_attach_failed;
+ }
+
+ /* Get the scatterlist for the given attachment */
+ table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR_OR_NULL(table)) {
+ rc = PTR_ERR(table) ?: -ENOMEM;
+ dprintk(VIDC_ERR, "Failed to map table\n");
+ goto mem_map_table_failed;
+ }
+
+ if (table->sgl) {
+ dprintk(VIDC_DBG,
+ "%s: DMA buf: %p, device: %p, attach: %p, table: %p, table sgl: %p, rc: %d, dma_address: %pa\n",
+ __func__, buf, cb->dev, attach,
+ table, table->sgl, rc,
+ &table->sgl->dma_address);
+
+ *iova = table->sgl->dma_address;
+ *buffer_size = table->sgl->dma_length;
+ } else {
+ dprintk(VIDC_ERR, "sgl is NULL\n");
+ rc = -ENOMEM;
+ goto mem_map_sg_failed;
+ }
+
+ /* Translation check for debugging */
+ orig_phys = sg_phys(table->sgl);
+
+ phys = iommu_iova_to_phys(cb->mapping->domain, *iova);
+ if (phys != orig_phys) {
+ dprintk(VIDC_ERR,
+ "%s iova_to_phys failed!!! mapped: %pa, got: %pa\n",
+ __func__, &orig_phys, &phys);
+ rc = -EIO;
+ goto mem_iova_to_phys_failed;
+ }
+
+ mapping_info->dev = cb->dev;
+ mapping_info->mapping = cb->mapping;
+ mapping_info->table = table;
+ mapping_info->attach = attach;
+ mapping_info->buf = buf;
+
+ dprintk(VIDC_DBG, "mapped dma buf %p to %pa\n", buf, iova);
+ return 0;
+mem_iova_to_phys_failed:
+ dma_unmap_sg(cb->dev, table->sgl, table->nents, DMA_BIDIRECTIONAL);
+mem_map_sg_failed:
+ dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
+mem_map_table_failed:
+ dma_buf_detach(buf, attach);
+mem_buf_attach_failed:
+ return rc;
+}
+
+static void put_device_address(struct smem_client *smem_client,
+ u32 flags, struct dma_mapping_info *mapping_info,
+ enum hal_buffer buffer_type)
+{
+ if (!smem_client || !mapping_info) {
+ dprintk(VIDC_WARN, "Invalid params: %p, %p\n",
+ smem_client, mapping_info);
+ return;
+ }
+
+ if (!mapping_info->dev || !mapping_info->table ||
+ !mapping_info->buf || !mapping_info->attach) {
+ dprintk(VIDC_WARN, "Invalid params:\n");
+ return;
+ }
+
+ if (is_iommu_present(smem_client->res)) {
+ dprintk(VIDC_DBG,
+ "Calling dma_unmap_sg - device: %p, address: %pa, buf: %p, table: %p, attach: %p\n",
+ mapping_info->dev,
+ &mapping_info->table->sgl->dma_address,
+ mapping_info->buf, mapping_info->table,
+ mapping_info->attach);
+
+ dma_buf_unmap_attachment(mapping_info->attach,
+ mapping_info->table, DMA_BIDIRECTIONAL);
+ dma_buf_detach(mapping_info->buf, mapping_info->attach);
+ dma_buf_put(mapping_info->buf);
+ }
+}
+
+#ifdef CONFIG_MSM_VIDC_USES_ION
+static int ion_get_device_address(struct smem_client *smem_client,
+ struct ion_handle *hndl, unsigned long align,
+ ion_phys_addr_t *iova, unsigned long *buffer_size,
+ unsigned long flags, enum hal_buffer buffer_type,
+ struct dma_mapping_info *mapping_info)
+{
+ int rc = 0;
+ struct dma_buf *buf = NULL;
+ struct context_bank_info *cb = NULL;
+ struct ion_client *clnt = smem_client->clnt;
+ if (!clnt) {
+ dprintk(VIDC_ERR, "Invalid client\n");
+ return -EINVAL;
+ }
+ cb = msm_smem_get_context_bank(smem_client, flags & SMEM_SECURE,
+ buffer_type);
+ if (!cb) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get context bank device\n",
+ __func__);
+ return -EIO;
+ }
+ if (is_iommu_present(smem_client->res)) {
+ /* Convert an Ion handle to a dma buf */
+ buf = ion_share_dma_buf(clnt, hndl);
+ if (IS_ERR_OR_NULL(buf)) {
+ rc = PTR_ERR(buf) ?: -ENOMEM;
+ dprintk(VIDC_ERR, "Share ION buf to DMA failed\n");
+ goto mem_map_failed;
+ }
+ rc = get_device_address(smem_client, buf, align, iova, buffer_size, flags, cb, mapping_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "ion iommu map failed - %d\n", rc);
+ goto mem_map_failed;
+ }
+ } else {
+ dprintk(VIDC_DBG, "Using physical memory address\n");
+ rc = ion_phys(clnt, hndl, iova, (size_t *)buffer_size);
+ if (rc) {
+ dprintk(VIDC_ERR, "ion memory map failed - %d\n", rc);
+ goto mem_map_failed;
+ }
+ }
+mem_map_failed:
+ return rc;
+}
+
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+ struct msm_smem *mem, enum hal_buffer buffer_type)
+{
+ struct ion_handle *hndl;
+ ion_phys_addr_t iova = 0;
+ unsigned long buffer_size = 0;
+ int rc = 0;
+ unsigned long align = SZ_4K;
+
+ hndl = ion_import_dma_buf(client->clnt, fd);
+ dprintk(VIDC_DBG, "%s ion handle: %p\n", __func__, hndl);
+ if (IS_ERR_OR_NULL(hndl)) {
+ dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
+ client, fd, offset, hndl);
+ rc = -ENOMEM;
+ goto fail_import_fd;
+ }
+ mem->kvaddr = NULL;
+ rc = ion_handle_get_flags(client->clnt, hndl, &mem->flags);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+ goto fail_device_address;
+ }
+
+ mem->buffer_type = buffer_type;
+ if (mem->flags & SMEM_SECURE)
+ align = ALIGN(align, SZ_1M);
+
+ rc = ion_get_device_address(client, hndl, align, &iova, &buffer_size,
+ mem->flags, buffer_type, &mem->mapping_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
+ goto fail_device_address;
+ }
+
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ mem->device_addr = iova;
+ mem->size = buffer_size;
+ if ((u32)mem->device_addr != iova) {
+ dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+ &iova, (u32)mem->device_addr);
+ goto fail_device_address;
+ }
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = %p, fd = %d, device_addr = %pa, size = %zx, kvaddr = %p, buffer_type = %d, flags = %#lx\n",
+ __func__, mem->smem_priv, fd, &mem->device_addr, mem->size,
+ mem->kvaddr, mem->buffer_type, mem->flags);
+ return rc;
+fail_device_address:
+ ion_free(client->clnt, hndl);
+fail_import_fd:
+ return rc;
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size, u32 align,
+ u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+ int map_kernel)
+{
+ struct ion_handle *hndl;
+ ion_phys_addr_t iova = 0;
+ unsigned long buffer_size = 0;
+ unsigned long heap_mask = 0;
+ int rc = 0;
+
+ align = ALIGN(align, SZ_4K);
+ size = ALIGN(size, SZ_4K);
+
+ if (flags & SMEM_SECURE) {
+ size = ALIGN(size, SZ_1M);
+ align = ALIGN(align, SZ_1M);
+ flags |= ION_FLAG_ALLOW_NON_CONTIG;
+ }
+
+ if (is_iommu_present(client->res)) {
+ heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID);
+ } else {
+ dprintk(VIDC_DBG,
+ "allocate shared memory from adsp heap size %zx align %d\n",
+ size, align);
+ heap_mask = ION_HEAP(ION_ADSP_HEAP_ID);
+ }
+
+ if (flags & SMEM_SECURE)
+ heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+
+ trace_msm_smem_buffer_ion_op_start("ALLOC", (u32)buffer_type,
+ heap_mask, size, align, flags, map_kernel);
+ hndl = ion_alloc(client->clnt, size, align, heap_mask, flags);
+ if (IS_ERR_OR_NULL(hndl)) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate shared memory = %p, %zx, %d, %#x\n",
+ client, size, align, flags);
+ rc = -ENOMEM;
+ goto fail_shared_mem_alloc;
+ }
+ trace_msm_smem_buffer_ion_op_end("ALLOC", (u32)buffer_type,
+ heap_mask, size, align, flags, map_kernel);
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ mem->flags = flags;
+ mem->buffer_type = buffer_type;
+ if (map_kernel) {
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+ if (IS_ERR_OR_NULL(mem->kvaddr)) {
+ dprintk(VIDC_ERR,
+ "Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ } else {
+ mem->kvaddr = NULL;
+ }
+
+ rc = ion_get_device_address(client, hndl, align, &iova, &buffer_size,
+ flags, buffer_type, &mem->mapping_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get device address: %d\n",
+ rc);
+ goto fail_device_address;
+ }
+ mem->device_addr = iova;
+ if ((u32)mem->device_addr != iova) {
+ dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+ &iova, (u32)mem->device_addr);
+ goto fail_device_address;
+ }
+ mem->size = size;
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = %p, device_addr = %pa, size = %#zx, kvaddr = %p, buffer_type = %#x, flags = %#lx\n",
+ __func__, mem->smem_priv, &mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type, mem->flags);
+ return rc;
+fail_device_address:
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, hndl);
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+ return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = %p, device_addr = %pa, size = %#zx, kvaddr = %p, buffer_type = %#x\n",
+ __func__, mem->smem_priv, &mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
+
+ if (mem->device_addr)
+ put_device_address(client, mem->flags,
+ &mem->mapping_info, mem->buffer_type);
+
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, mem->smem_priv);
+ if (mem->smem_priv) {
+ trace_msm_smem_buffer_ion_op_start("FREE",
+ (u32)mem->buffer_type, -1, mem->size, -1,
+ mem->flags, -1);
+ dprintk(VIDC_DBG,
+ "%s: Freeing handle %p, client: %p\n",
+ __func__, mem->smem_priv, client->clnt);
+ ion_free(client->clnt, mem->smem_priv);
+ trace_msm_smem_buffer_ion_op_end("FREE", (u32)mem->buffer_type,
+ -1, mem->size, -1, mem->flags, -1);
+ }
+}
+
+static void *ion_new_client(void)
+{
+ struct ion_client *client = NULL;
+ client = msm_ion_client_create("video_client");
+ if (!client)
+ dprintk(VIDC_ERR, "Failed to create smem client\n");
+ return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+ ion_client_destroy(client->clnt);
+}
+
+static int ion_cache_operations(struct smem_client *client,
+ struct msm_smem *mem, enum smem_cache_ops cache_op)
+{
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+ if (!mem || !client) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+ mem, client);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(client->clnt, mem->smem_priv,
+ &ionflag);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+ if (ION_IS_CACHED(ionflag)) {
+ switch (cache_op) {
+ case SMEM_CACHE_CLEAN:
+ msm_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case SMEM_CACHE_INVALIDATE:
+ msm_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case SMEM_CACHE_CLEAN_INVALIDATE:
+ msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ dprintk(VIDC_ERR, "cache operation not supported\n");
+ rc = -EINVAL;
+ goto cache_op_failed;
+ }
+ rc = msm_ion_do_cache_op(client->clnt,
+ (struct ion_handle *)mem->smem_priv,
+ 0, (unsigned long)mem->size,
+ msm_cache_ops);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ }
+cache_op_failed:
+ return rc;
+}
+#endif
+
+static int alloc_dma_mem(struct smem_client *client, size_t size, u32 align,
+ u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+ int map_kernel)
+{
+ int rc = 0;
+ enum dma_data_direction dma_dir;
+ unsigned long buffer_size = 0;
+ struct context_bank_info *cb = NULL;
+
+ align = ALIGN(align, SZ_4K);
+ size = ALIGN(size, SZ_4K);
+ size = PAGE_ALIGN(size);
+
+ dprintk(VIDC_DBG, "alloc_dma_mem type %d, size %zu\n", buffer_type, size);
+
+ switch (buffer_type) {
+ case HAL_BUFFER_INPUT:
+ dma_dir = DMA_TO_DEVICE;
+ break;
+ case HAL_BUFFER_OUTPUT:
+ dma_dir = DMA_FROM_DEVICE;
+ break;
+ default:
+ dma_dir = DMA_FROM_DEVICE;
+ break;
+ }
+
+ mem->mem_type = client->mem_type;
+ mem->flags = flags;
+ mem->buffer_type = buffer_type;
+ mem->kvaddr = NULL;
+ mem->size = size;
+
+ cb = msm_smem_get_context_bank(client, flags & SMEM_SECURE,
+ buffer_type);
+ if (!cb) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get context bank device\n",
+ __func__);
+ return -EIO;
+ }
+
+ mem->smem_priv = vb2_dma_contig_memops.alloc(cb->alloc_ctx, size, dma_dir, 0);
+ if (IS_ERR_OR_NULL(mem->smem_priv)) {
+ dprintk(VIDC_ERR, "VB2 contig memops alloc failed %zu\n", size);
+ rc = PTR_ERR(mem->smem_priv) ?: -ENOMEM;
+ goto err_dma_alloc;
+ }
+
+ dprintk(VIDC_DBG, "alloc_dma_mem, map_kernel\n");
+ mem->kvaddr = vb2_dma_contig_memops.vaddr(mem->smem_priv);
+ if (!mem->kvaddr) {
+ dprintk(VIDC_WARN, "Failed to map dma buf %pad\n", &mem->device_addr);
+ rc = -ENOMEM;
+ goto err_put;
+ }
+
+ //rc = dma_get_sgtable(&res->pdev->dev, &mem->mapping_info.table, mem->kvaddr, mem->device_addr, size);
+ rc = get_device_address(client, vb2_dma_contig_memops.get_dmabuf(mem->smem_priv, O_CLOEXEC),
+ &mem->device_addr, &buffer_size, flags, cb, &mem->mapping_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get iova for dma buf %pad\n",
+ vb2_dma_contig_memops.cookie(mem->smem_priv));
+ goto err_put;
+ }
+
+ dprintk(VIDC_DBG,
+ "%s: dma_handle = %p, device_addr = %pad, size = %#zx, kvaddr = %p, buffer_type = %#x, flags = %#lx\n",
+ __func__, mem->smem_priv, &mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type, mem->flags);
+
+ dprintk(VIDC_DBG,
+ "%s: sg_handle = 0x%p, device_addr = 0x%x, size = %zu, kvaddr = 0x%p, buffer_type = %d\n",
+ __func__, mem->smem_priv, (u32)mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
+ return rc;
+err_put:
+ vb2_dma_contig_memops.put(mem->smem_priv);
+err_dma_alloc:
+ mem->smem_priv = NULL;
+ return rc;
+}
+
+static void free_dma_mem(struct smem_client *client, struct msm_smem *mem)
+{
+ dprintk(VIDC_DBG,
+ "%s: mem priv = 0x%p, device_addr = 0x%pa, size = 0x%zx, kvaddr = 0x%p, buffer_type = 0x%x\n",
+ __func__, mem->smem_priv, &mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
+ if (mem->device_addr)
+ put_device_address(client, mem->flags,
+ &mem->mapping_info, mem->buffer_type);
+ if (mem->smem_priv) {
+ vb2_dma_contig_memops.put(mem->smem_priv);
+ mem->smem_priv = NULL;
+ }
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+ enum hal_buffer buffer_type)
+{
+ struct smem_client *client = clt;
+ int rc = 0;
+ struct msm_smem *mem;
+ if (fd < 0) {
+ dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ dprintk(VIDC_ERR, "Failed to allocte shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+ break;
+#endif
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops cache_op)
+{
+ struct smem_client *client = clt;
+ int rc = 0;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n",
+ client);
+ return -EINVAL;
+ }
+ switch (client->mem_type) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ rc = ion_cache_operations(client, mem, cache_op);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed cache operations: %d\n", rc);
+ break;
+#endif
+ case SMEM_DMA:
+ dprintk(VIDC_DBG,
+ "Ignore dma cache operations: %d\n", rc);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ break;
+ }
+ return rc;
+}
+
+void *msm_smem_new_client(enum smem_type mtype,
+ void *platform_resources)
+{
+ struct smem_client *client = NULL;
+ void *clnt = NULL;
+ struct msm_vidc_platform_resources *res = platform_resources;
+ switch (mtype) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ clnt = ion_new_client();
+ break;
+#endif
+ case SMEM_DMA:
+ clnt = vb2_dma_contig_init_ctx(&(res->pdev->dev));
+ break;
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ break;
+ }
+ if (clnt) {
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client) {
+ client->mem_type = mtype;
+ client->clnt = clnt;
+ client->res = res;
+ }
+ } else {
+ dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
+ mtype);
+ }
+ return client;
+}
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ struct smem_client *client;
+ int rc = 0;
+ struct msm_smem *mem;
+ client = clt;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid client passed\n");
+ return NULL;
+ }
+ if (!size) {
+ dprintk(VIDC_ERR, "No need to allocate memory of size: %zx\n",
+ size);
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ rc = alloc_ion_mem(client, size, align, flags, buffer_type,
+ mem, map_kernel);
+ break;
+#endif
+ case SMEM_DMA:
+ rc = alloc_dma_mem(client, size, align, flags, buffer_type,
+ mem, map_kernel);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+ struct smem_client *client = clt;
+ if (!client || !mem) {
+ dprintk(VIDC_ERR, "Invalid client/handle passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ free_ion_mem(client, mem);
+ break;
+#endif
+ case SMEM_DMA:
+ free_dma_mem(client, mem);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ break;
+ }
+ kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+ struct smem_client *client = clt;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid client passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+#ifdef CONFIG_MSM_VIDC_USES_ION
+ case SMEM_ION:
+ ion_delete_client(client);
+ break;
+#endif
+ case SMEM_DMA:
+ vb2_dma_contig_cleanup_ctx(client->clnt);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Mem type not supported\n");
+ break;
+ }
+ kfree(client);
+}
+
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+ bool is_secure, enum hal_buffer buffer_type)
+{
+ struct smem_client *client = clt;
+ struct context_bank_info *cb = NULL, *match = NULL;
+
+ if (!clt) {
+ dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+ return NULL;
+ }
+
+ list_for_each_entry(cb, &client->res->context_banks, list) {
+ if (cb->is_secure == is_secure &&
+ cb->buffer_type & buffer_type) {
+ match = cb;
+ dprintk(VIDC_DBG,
+ "context bank found for CB : %s, device: %p mapping: %p\n",
+ match->name, match->dev, match->mapping);
+ break;
+ }
+ }
+
+ return match;
+}
+
+void *msm_smem_get_alloc_ctx(void *mem_client)
+{
+ struct smem_client *client = mem_client;
+ return client->clnt;
+}
+
+
+struct msm_smem* msm_smem_map_dma_buf(void* smem_client, struct dma_buf* dbuf,
+ enum hal_buffer buffer_type)
+{
+ struct smem_client *client = smem_client;
+ int rc = 0;
+ struct msm_smem *mem;
+ unsigned long buffer_size = 0;
+ u32 flags = 0;
+ struct context_bank_info *cb = NULL;
+
+ dprintk(VIDC_DBG, "msm_smem_map_dma_buf type %d\n", buffer_type);
+
+ if (client == NULL || dbuf == NULL) {
+ dprintk(VIDC_ERR, "%s: Invalid params \n", __func__);
+ return NULL;
+ }
+
+ if (is_iommu_present(client->res)) {
+ cb = msm_smem_get_context_bank(smem_client, flags & SMEM_SECURE,
+ buffer_type);
+ if (!cb) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get context bank device\n",
+ __func__);
+ return NULL;
+ }
+ }
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ dprintk(VIDC_ERR, "Failed to allocte shared mem\n");
+ return NULL;
+ }
+
+ rc = get_device_address(client, dbuf, &mem->device_addr, &buffer_size,
+ flags, cb, &mem->mapping_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get iova for dma buf %pad\n", dbuf);
+ goto err_get_device_address;
+ }
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = NULL;
+ mem->size = buffer_size;
+ mem->kvaddr = NULL;
+ mem->buffer_type = buffer_type;
+
+ return mem;
+err_get_device_address:
+ kfree(mem);
+ mem = NULL;
+ return ERR_PTR(rc);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
new file mode 100644
index 000000000000..ac421b41c9fa
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -0,0 +1,816 @@
+/* Copyright (c) 2012-2015, 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/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/msm_iommu_domains.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_iommu.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_common.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_res_parse.h"
+#include "msm_vidc_resources.h"
+#include "venus_boot.h"
+#include "vidc_hfi_api.h"
+
+#define BASE_DEVICE_NUMBER 32
+#define EARLY_FIRMWARE_LOAD_DELAY 1000
+
+struct msm_vidc_drv *vidc_driver;
+
+uint32_t msm_vidc_pwr_collapse_delay = 2000;
+
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+ return container_of(filp->private_data,
+ struct msm_vidc_inst, event_handler);
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct msm_video_device *vid_dev =
+ container_of(vdev, struct msm_video_device, vdev);
+ struct msm_vidc_core *core = video_drvdata(filp);
+ struct msm_vidc_inst *vidc_inst;
+
+ trace_msm_v4l2_vidc_open_start("msm_v4l2_open start");
+ vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+ if (!vidc_inst) {
+ dprintk(VIDC_ERR,
+ "Failed to create video instance, core: %d, type = %d\n",
+ core->id, vid_dev->type);
+ return -ENOMEM;
+ }
+ clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+ filp->private_data = &(vidc_inst->event_handler);
+ trace_msm_v4l2_vidc_open_end("msm_v4l2_open end");
+ return 0;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst;
+
+ trace_msm_v4l2_vidc_close_start("msm_v4l2_close start");
+ vidc_inst = get_vidc_inst(filp, NULL);
+ rc = msm_vidc_release_buffers(vidc_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
+
+ rc = msm_vidc_close(vidc_inst);
+ trace_msm_v4l2_vidc_close_end("msm_v4l2_close end");
+ return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+ return msm_vidc_querycap((void *)vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_enum_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_g_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_g_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_s_ext_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_controls *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_ext_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ if (!b->count)
+ rc = msm_vidc_release_buffers(vidc_inst, b->type);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
+ return msm_vidc_reqbufs((void *)vidc_inst, b);
+}
+
+int msm_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ return msm_vidc_querybuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_streamon((void *)vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ struct msm_vidc_inst *vidc_inst = container_of(fh,
+ struct msm_vidc_inst, event_handler);
+ return msm_vidc_subscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ struct msm_vidc_inst *vidc_inst = container_of(fh,
+ struct msm_vidc_inst, event_handler);
+ return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+ struct v4l2_decoder_cmd *dec)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ if (dec->cmd == V4L2_DEC_CMD_STOP)
+ rc = msm_vidc_release_buffers(vidc_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to release dec output buffers: %d\n", rc);
+ return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
+}
+
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ if (enc->cmd == V4L2_ENC_CMD_STOP)
+ rc = msm_vidc_release_buffers(vidc_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to release enc output buffers: %d\n", rc);
+ return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
+}
+static int msm_v4l2_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_parm((void *)vidc_inst, a);
+}
+static int msm_v4l2_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ return 0;
+}
+
+static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
+}
+
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ .vidioc_querycap = msm_v4l2_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+ .vidioc_reqbufs = msm_v4l2_reqbufs,
+ .vidioc_querybuf = msm_v4l2_querybuf,
+ .vidioc_prepare_buf = msm_v4l2_prepare_buf,
+ .vidioc_qbuf = msm_v4l2_qbuf,
+ .vidioc_dqbuf = msm_v4l2_dqbuf,
+ .vidioc_streamon = msm_v4l2_streamon,
+ .vidioc_streamoff = msm_v4l2_streamoff,
+ .vidioc_s_ctrl = msm_v4l2_s_ctrl,
+ .vidioc_g_ctrl = msm_v4l2_g_ctrl,
+ .vidioc_s_ext_ctrls = msm_v4l2_s_ext_ctrl,
+ .vidioc_subscribe_event = msm_v4l2_subscribe_event,
+ .vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+ .vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+ .vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
+ .vidioc_s_parm = msm_v4l2_s_parm,
+ .vidioc_g_parm = msm_v4l2_g_parm,
+ .vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+ struct poll_table_struct *pt)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+ return msm_vidc_poll((void *)vidc_inst, filp, pt);
+}
+
+static int msm_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, NULL);
+ int rc = msm_vidc_mmap(vidc_inst, vma);
+ if (rc) {
+ dprintk(VIDC_ERR, "msm_vidc_mmap error %d \n", rc);
+ }
+ return rc;
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_v4l2_open,
+ .release = msm_v4l2_close,
+ .ioctl = video_ioctl2,
+ .poll = msm_v4l2_poll,
+ .mmap = msm_v4l2_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = v4l2_compat_ioctl32,
+#endif
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int read_platform_resources(struct msm_vidc_core *core,
+ struct platform_device *pdev)
+{
+ if (!core || !pdev) {
+ dprintk(VIDC_ERR, "%s: Invalid params %p %p\n",
+ __func__, core, pdev);
+ return -EINVAL;
+ }
+ core->hfi_type = read_hfi_type(pdev);
+ if (core->hfi_type < 0) {
+ dprintk(VIDC_ERR, "Failed to identify core type\n");
+ return core->hfi_type;
+ }
+
+ core->resources.pdev = pdev;
+ if (pdev->dev.of_node) {
+ /* Target supports DT, parse from it */
+ return read_platform_resources_from_dt(&core->resources);
+ } else {
+ dprintk(VIDC_ERR, "pdev node is NULL\n");
+ return -EINVAL;
+ }
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ int i = 0;
+ int rc = 0;
+ if (!core)
+ return -EINVAL;
+ rc = read_platform_resources(core, pdev);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get platform resources\n");
+ return rc;
+ }
+
+ INIT_LIST_HEAD(&core->instances);
+ mutex_init(&core->lock);
+
+ core->state = VIDC_CORE_UNINIT;
+ for (i = SYS_MSG_INDEX(SYS_MSG_START);
+ i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+ init_completion(&core->completions[i]);
+ }
+
+ INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
+ return rc;
+}
+
+static ssize_t msm_vidc_link_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct msm_vidc_core *core = dev_get_drvdata(dev);
+ if (core)
+ if (dev == &core->vdev[MSM_VIDC_DECODER].vdev.dev)
+ if (core->hfi_type == VIDC_HFI_Q6)
+ return snprintf(buf, PAGE_SIZE, "q6_dec");
+ else
+ return snprintf(buf, PAGE_SIZE, "venus_dec");
+ else if (dev == &core->vdev[MSM_VIDC_ENCODER].vdev.dev)
+ if (core->hfi_type == VIDC_HFI_Q6)
+ return snprintf(buf, PAGE_SIZE, "q6_enc");
+ else
+ return snprintf(buf, PAGE_SIZE, "venus_enc");
+ else
+ return 0;
+ else
+ return 0;
+}
+
+static DEVICE_ATTR(link_name, 0444, msm_vidc_link_name_show, NULL);
+
+static ssize_t store_pwr_collapse_delay(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long val = 0;
+ int rc = 0;
+ rc = kstrtoul(buf, 0, &val);
+ if (rc)
+ return rc;
+ else if (!val)
+ return -EINVAL;
+ msm_vidc_pwr_collapse_delay = val;
+ return count;
+}
+
+static ssize_t show_pwr_collapse_delay(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", msm_vidc_pwr_collapse_delay);
+}
+
+static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay,
+ store_pwr_collapse_delay);
+
+static ssize_t show_thermal_level(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level);
+}
+
+static ssize_t store_thermal_level(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc = 0, val = 0;
+
+ rc = kstrtoint(buf, 0, &val);
+ if (rc || val < 0) {
+ dprintk(VIDC_WARN,
+ "Invalid thermal level value: %s\n", buf);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "Thermal level old %d new %d\n",
+ vidc_driver->thermal_level, val);
+
+ if (val == vidc_driver->thermal_level)
+ return count;
+ vidc_driver->thermal_level = val;
+
+ msm_comm_handle_thermal_event();
+ return count;
+}
+
+static DEVICE_ATTR(thermal_level, S_IRUGO | S_IWUSR, show_thermal_level,
+ store_thermal_level);
+
+static struct attribute *msm_vidc_core_attrs[] = {
+ &dev_attr_pwr_collapse_delay.attr,
+ &dev_attr_thermal_level.attr,
+ NULL
+};
+
+static struct attribute_group msm_vidc_core_attr_group = {
+ .attrs = msm_vidc_core_attrs,
+};
+
+static const struct of_device_id msm_vidc_dt_match[] = {
+ {.compatible = "qcom,msm-vidc"},
+ {.compatible = "qcom,msm-vidc,context-bank"},
+ {}
+};
+
+struct fw_load_handler_data {
+ struct msm_vidc_core *core;
+ struct delayed_work work;
+};
+
+
+static void fw_load_handler(struct work_struct *work)
+{
+ struct msm_vidc_core *core = NULL;
+ struct fw_load_handler_data *handler = NULL;
+ int rc = 0;
+
+ handler = container_of(work, struct fw_load_handler_data,
+ work.work);
+ if (!handler || !handler->core) {
+ dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+ __func__);
+ goto exit;
+ }
+ core = handler->core;
+
+ rc = msm_comm_load_fw(core);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to load fw\n", __func__);
+ goto exit;
+ }
+
+ rc = msm_comm_check_core_init(core);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to init core\n", __func__);
+ goto exit;
+ }
+ dprintk(VIDC_DBG, "%s - firmware loaded successfully\n", __func__);
+
+exit:
+ kfree(handler);
+}
+
+static void load_firmware(struct msm_vidc_core *core)
+{
+ struct fw_load_handler_data *handler = NULL;
+
+ handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+ if (!handler) {
+ dprintk(VIDC_ERR,
+ "%s - failed to allocate sys error handler\n",
+ __func__);
+ return;
+ }
+ handler->core = core;
+ INIT_DELAYED_WORK(&handler->work, fw_load_handler);
+ schedule_delayed_work(&handler->work,
+ msecs_to_jiffies(EARLY_FIRMWARE_LOAD_DELAY));
+}
+
+static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+ struct device *dev;
+ int nr = BASE_DEVICE_NUMBER;
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core || !vidc_driver) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate memory for device core\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ dev_set_drvdata(&pdev->dev, core);
+ rc = msm_vidc_initialize_core(pdev, core);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to init core\n");
+ goto err_core_init;
+ }
+ rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to create attributes\n");
+ goto err_core_init;
+ }
+ if (core->hfi_type == VIDC_HFI_Q6) {
+ dprintk(VIDC_DBG, "Q6 hfi device probe called\n");
+ nr += MSM_VIDC_MAX_DEVICES;
+ core->id = MSM_VIDC_CORE_Q6;
+ } else {
+ core->id = MSM_VIDC_CORE_VENUS;
+ }
+
+ rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
+ goto err_v4l2_register;
+ }
+
+ /* setup the decoder device */
+ core->vdev[MSM_VIDC_DECODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_DECODER].vdev.vfl_dir = VFL_DIR_M2M;
+ core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+ core->vdev[MSM_VIDC_DECODER].vdev.v4l2_dev = &core->v4l2_dev;
+ rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+ VFL_TYPE_GRABBER, nr);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to register video decoder device");
+ goto err_dec_register;
+ }
+
+ video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+ dev = &core->vdev[MSM_VIDC_DECODER].vdev.dev;
+ rc = device_create_file(dev, &dev_attr_link_name);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to create link name sysfs for decoder");
+ goto err_dec_attr_link_name;
+ }
+
+ /* setup the encoder device */
+ core->vdev[MSM_VIDC_ENCODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_ENCODER].vdev.vfl_dir = VFL_DIR_M2M;
+ core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+ core->vdev[MSM_VIDC_ENCODER].vdev.v4l2_dev = &core->v4l2_dev;
+ rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+ VFL_TYPE_GRABBER, nr + 1);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to register video encoder device");
+ goto err_enc_register;
+ }
+
+ video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+ dev = &core->vdev[MSM_VIDC_ENCODER].vdev.dev;
+ rc = device_create_file(dev, &dev_attr_link_name);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to create link name sysfs for encoder");
+ goto err_enc_attr_link_name;
+ }
+
+ /* finish setting up the 'core' */
+ mutex_lock(&vidc_driver->lock);
+ if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
+ mutex_unlock(&vidc_driver->lock);
+ dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
+ vidc_driver->num_cores);
+ goto err_cores_exceeded;
+ }
+ vidc_driver->num_cores++;
+ mutex_unlock(&vidc_driver->lock);
+
+ core->device = vidc_hfi_initialize(core->hfi_type, core->id,
+ &core->resources, &handle_cmd_response);
+ if (IS_ERR_OR_NULL(core->device)) {
+ mutex_lock(&vidc_driver->lock);
+ vidc_driver->num_cores--;
+ mutex_unlock(&vidc_driver->lock);
+
+ rc = PTR_ERR(core->device) ?: -EBADHANDLE;
+ if (rc != -EPROBE_DEFER)
+ dprintk(VIDC_ERR, "Failed to create HFI device\n");
+ else
+ dprintk(VIDC_DBG, "msm_vidc: request probe defer\n");
+ goto err_cores_exceeded;
+ }
+
+ mutex_lock(&vidc_driver->lock);
+ list_add_tail(&core->list, &vidc_driver->cores);
+ mutex_unlock(&vidc_driver->lock);
+
+ core->debugfs_root = msm_vidc_debugfs_init_core(
+ core, vidc_driver->debugfs_root);
+
+ dprintk(VIDC_DBG, "populating sub devices\n");
+ /*
+ * Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank.
+ * When msm_vidc_probe is called for each sub-device, parse the
+ * context-bank details and store it in core->resources.context_banks
+ * list.
+ */
+ rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
+ &pdev->dev);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to trigger probe for sub-devices\n");
+ goto err_fail_sub_device_probe;
+ }
+
+ if (core->resources.early_fw_load)
+ load_firmware(core);
+
+ return rc;
+
+err_fail_sub_device_probe:
+ vidc_hfi_deinitialize(core->hfi_type, core->device);
+err_cores_exceeded:
+ device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+ &dev_attr_link_name);
+err_enc_attr_link_name:
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+ device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+ &dev_attr_link_name);
+err_dec_attr_link_name:
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+ v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+ sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+err_core_init:
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(core);
+err_no_mem:
+ return rc;
+}
+
+static int msm_vidc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ /*
+ * Sub devices probe will be triggered by of_platform_populate()
+ * towards the end of the probe function after msm-vidc device
+ * probe is completed. Return immediately after completing sub-device
+ * probe.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "qcom,msm-vidc,context-bank")) {
+ rc = msm_vidc_probe_sub_devices(pdev);
+ if (rc)
+ dprintk(VIDC_ERR, "sub-devices probe failed\n");
+ return rc;
+ }
+
+ return msm_vidc_probe_vidc_device(pdev);
+}
+
+static int msm_vidc_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+
+ if (!pdev) {
+ dprintk(VIDC_ERR, "%s invalid input %p", __func__, pdev);
+ return -EINVAL;
+ }
+
+ core = dev_get_drvdata(&pdev->dev);
+ if (!core) {
+ dprintk(VIDC_ERR, "%s invalid core", __func__);
+ return -EINVAL;
+ }
+
+ if (core->resources.use_non_secure_pil)
+ venus_boot_deinit();
+
+ vidc_hfi_deinitialize(core->hfi_type, core->device);
+ device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+ &dev_attr_link_name);
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+ device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+ &dev_attr_link_name);
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+ v4l2_device_unregister(&core->v4l2_dev);
+
+ msm_vidc_free_platform_resources(&core->resources);
+ sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(core);
+ return rc;
+}
+
+static int msm_vidc_pm_suspend(struct device *dev)
+{
+ struct msm_vidc_core *core;
+
+ if (!dev || !dev->driver) {
+ /* driver possibly not probed yet */
+ return 0;
+ }
+
+ core = dev_get_drvdata(dev);
+ if (!core) {
+ dprintk(VIDC_ERR, "%s invalid core\n", __func__);
+ return -EINVAL;
+ }
+
+ dprintk(VIDC_INFO, "%s\n", __func__);
+ return msm_vidc_suspend(core->id);
+}
+
+static int msm_vidc_pm_resume(struct device *dev)
+{
+ dprintk(VIDC_INFO, "%s\n", __func__);
+ return 0;
+}
+
+static const struct dev_pm_ops msm_vidc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume)
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+ .probe = msm_vidc_probe,
+ .remove = msm_vidc_remove,
+ .driver = {
+ .name = "msm_vidc_v4l2",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_vidc_dt_match,
+ .pm = &msm_vidc_pm_ops,
+ },
+};
+
+static int __init msm_vidc_init(void)
+{
+ int rc = 0;
+ vidc_driver = kzalloc(sizeof(*vidc_driver),
+ GFP_KERNEL);
+ if (!vidc_driver) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate memroy for msm_vidc_drv\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vidc_driver->cores);
+ mutex_init(&vidc_driver->lock);
+ vidc_driver->debugfs_root = msm_vidc_debugfs_init_drv();
+ if (!vidc_driver->debugfs_root)
+ dprintk(VIDC_ERR,
+ "Failed to create debugfs for msm_vidc\n");
+
+ rc = platform_driver_register(&msm_vidc_driver);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to register platform driver\n");
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+ platform_driver_unregister(&msm_vidc_driver);
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
new file mode 100644
index 000000000000..9d1f067ff721
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -0,0 +1,2779 @@
+/* Copyright (c) 2012-2015, 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/slab.h>
+#include <linux/qcom_scm.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
+#define MB_SIZE_IN_PIXEL (16 * 16)
+
+#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
+#define TZ_FEATURE_VERSION(major, minor, patch) \
+ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+ "DIVX Format 3",
+ "DIVX Format 4",
+ "DIVX Format 5",
+ "DIVX Format 6",
+ NULL
+};
+static const char *mpeg_video_stream_format[] = {
+ "NAL Format Start Codes",
+ "NAL Format One NAL Per Buffer",
+ "NAL Format One Byte Length",
+ "NAL Format Two Byte Length",
+ "NAL Format Four Byte Length",
+ NULL
+};
+static const char *const mpeg_video_output_order[] = {
+ "Display Order",
+ "Decode Order",
+ NULL
+};
+static const char *const mpeg_video_vidc_extradata[] = {
+ "Extradata none",
+ "Extradata MB Quantization",
+ "Extradata Interlace Video",
+ "Extradata VC1 Framedisp",
+ "Extradata VC1 Seqdisp",
+ "Extradata timestamp",
+ "Extradata S3D Frame Packing",
+ "Extradata Frame Rate",
+ "Extradata Panscan Window",
+ "Extradata Recovery point SEI",
+ "Extradata Closed Caption UD",
+ "Extradata AFD UD",
+ "Extradata Multislice info",
+ "Extradata number of concealed MB",
+ "Extradata metadata filler",
+ "Extradata input crop",
+ "Extradata digital zoom",
+ "Extradata aspect ratio",
+ "Extradata mpeg2 seqdisp",
+};
+static const char *const mpeg_vidc_video_alloc_mode_type[] = {
+ "Buffer Allocation Static",
+ "Buffer Allocation Ring Buffer",
+ "Buffer Allocation Dynamic Buffer"
+};
+
+static const char *const perf_level[] = {
+ "Nominal",
+ "Performance",
+ "Turbo"
+};
+
+static const char *const h263_level[] = {
+ "1.0",
+ "2.0",
+ "3.0",
+ "4.0",
+ "4.5",
+ "5.0",
+ "6.0",
+ "7.0",
+};
+
+static const char *const h263_profile[] = {
+ "Baseline",
+ "H320 Coding",
+ "Backward Compatible",
+ "ISWV2",
+ "ISWV3",
+ "High Compression",
+ "Internet",
+ "Interlace",
+ "High Latency",
+};
+
+static const char *const vp8_profile_level[] = {
+ "Unused",
+ "0.0",
+ "1.0",
+ "2.0",
+ "3.0",
+};
+
+static const char *const mpeg2_profile[] = {
+ "Simple",
+ "Main",
+ "422",
+ "SNR scalable",
+ "Spatial scalable",
+ "High",
+};
+
+static const char *const mpeg2_level[] = {
+ "Level 0",
+ "Level 1",
+ "Level 2",
+ "Level 3",
+};
+
+static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
+ "Frame packing arrangement sequential",
+ "Frame packing arrangement top-bottom",
+};
+
+static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+ .name = "NAL Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+ ),
+ .qmenu = mpeg_video_stream_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+ .name = "Output Order",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+ ),
+ .qmenu = mpeg_video_output_order,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
+ .name = "Picture Type Decoding",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 15,
+ .default_value = 15,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+ .name = "Keep Aspect Ratio",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+ .name = "Deblocker Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+ .name = "Divx Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+ ),
+ .qmenu = mpeg_video_vidc_divx_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+ .name = "MB Error Map Reporting",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+ .name = "control",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
+ .name = "Sync Frame Decode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+ .name = "Secure mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .default_value = 0,
+ .step = 0,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+ .name = "Extradata Type",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .maximum = V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO,
+ .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO)
+ ),
+ .qmenu = mpeg_video_vidc_extradata,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+ .name = "Decoder Performance Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+ .default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+ .qmenu = perf_level,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+ .name = "Buffer allocation mode for input",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+ ),
+ .qmenu = mpeg_vidc_video_alloc_mode_type,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+ .name = "Buffer allocation mode for output",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+ ),
+ .qmenu = mpeg_vidc_video_alloc_mode_type,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
+ .name = "Video frame assembly",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+ .maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE,
+ .default_value = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
+ .name = "Video decoder multi stream",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ .maximum =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
+ .default_value =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ .menu_skip_mask = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .name = "MPEG4 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum =
+ V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .name = "MPEG4 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .name = "H264 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .name = "H264 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .menu_skip_mask = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ .name = "H263 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+ ),
+ .qmenu = h263_profile,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ .name = "H263 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+ ),
+ .qmenu = h263_level,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ .name = "VP8 Profile Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+ ),
+ .qmenu = vp8_profile_level,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE,
+ .name = "MPEG2 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+ .menu_skip_mask = 0,
+ .qmenu = mpeg2_profile,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL,
+ .name = "MPEG2 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+ .menu_skip_mask = 0,
+ .qmenu = mpeg2_level,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD,
+ .name = "Video start code search threshold",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = INT_MAX,
+ .default_value = INT_MAX,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT,
+ .name = "MVC buffer layout",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM)
+ ),
+ .qmenu = mpeg_vidc_video_h264_mvc_layout,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
+ .name = "Picture concealed color",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0x0,
+ .maximum = 0xffffff,
+ .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT,
+ .name = "Buffer size limit",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD,
+ .name = "Secure scaling output2 threshold",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .flags = V4L2_CTRL_FLAG_VOLATILE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2,
+ .name = "Non-Secure output2",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static u32 get_frame_size_nv12(int plane,
+ u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane,
+ u32 max_mbs_per_frame, u32 size_per_mb)
+{
+ return (max_mbs_per_frame * size_per_mb * 3/2)/2;
+}
+
+static u32 get_frame_size(struct msm_vidc_inst *inst,
+ const struct msm_vidc_format *fmt,
+ int fmt_type, int plane)
+{
+ u32 frame_size = 0;
+ if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ frame_size = fmt->get_frame_size(plane,
+ inst->capability.mbs_per_frame.max,
+ MB_SIZE_IN_PIXEL);
+ if (inst->capability.buffer_size_limit &&
+ (inst->capability.buffer_size_limit < frame_size)) {
+ frame_size = inst->capability.buffer_size_limit;
+ dprintk(VIDC_DBG, "input buffer size limited to %d\n",
+ frame_size);
+ } else {
+ dprintk(VIDC_DBG, "set input buffer size to %d\n",
+ frame_size);
+ }
+ } else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ frame_size = fmt->get_frame_size(plane,
+ inst->capability.height.max,
+ inst->capability.width.max);
+ dprintk(VIDC_DBG, "set output buffer size to %d\n",
+ frame_size);
+ } else {
+ dprintk(VIDC_WARN, "Wrong format type\n");
+ }
+ return frame_size;
+}
+
+static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
+ struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+ if (inst->fmts[OUTPUT_PORT]->fourcc != V4L2_PIX_FMT_H264_MVC) {
+ dprintk(VIDC_ERR, "Control %#x only valid for MVC\n",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
+ ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
+ dprintk(VIDC_ERR,
+ "Profile %#x not supported for MVC\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
+ ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
+ dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+struct msm_vidc_format vdec_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1, /* TODO: was 2 */
+ .get_frame_size = get_frame_size_nv12,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "UBWC YCbCr Semiplanar 4:2:0",
+ .description = "UBWC Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12_UBWC,
+ .num_planes = 1, /* TODO: was 2 */
+ .get_frame_size = get_frame_size_nv12_ubwc,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg2",
+ .description = "Mpeg2 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "VC1",
+ .description = "VC-1 compressed format",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "VC1 SP",
+ .description = "VC-1 compressed format G",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H264_MVC",
+ .description = "H264_MVC compressed format",
+ .fourcc = V4L2_PIX_FMT_H264_MVC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "HEVC",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "HEVC_HYBRID",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "VP8",
+ .description = "VP8 compressed format",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "DIVX 311",
+ .description = "DIVX 311 compressed format",
+ .fourcc = V4L2_PIX_FMT_DIVX_311,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "DIVX",
+ .description = "DIVX 4/5/6 compressed format",
+ .fourcc = V4L2_PIX_FMT_DIVX,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ }
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct buf_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "Calling streamon\n");
+ mutex_lock(&q->lock);
+ rc = vb2_streamon(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct buf_queue *q;
+
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "Calling streamoff\n");
+ mutex_lock(&q->lock);
+ rc = vb2_streamoff(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ struct vidc_buffer_addr_info buffer_info;
+ int extra_idx = 0;
+ int i;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core %p in bad state, ignoring prepare buf\n",
+ inst->core);
+ goto exit;
+ }
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); ++i) {
+ dprintk(VIDC_DBG,
+ "prepare plane: %d, device_addr = %#lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ }
+
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+ b->m.planes[extra_idx].m.userptr) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
+ dprintk(VIDC_DBG, "extradata: %pa, length = %d\n",
+ &buffer_info.extradata_addr,
+ buffer_info.extradata_size);
+ } else {
+ buffer_info.extradata_addr = 0;
+ buffer_info.extradata_size = 0;
+ }
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+exit:
+ return rc;
+}
+
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ struct vidc_buffer_addr_info buffer_info;
+ struct msm_vidc_core *core;
+ int extra_idx = 0;
+ int i;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ core = inst->core;
+ hdev = inst->core->device;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core %p in bad state, ignoring release output buf\n",
+ core);
+ goto exit;
+ }
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes, b->length);
+ rc = -EINVAL;
+ break;
+ }
+
+ for (i = 0; i < b->length; ++i) {
+ dprintk(VIDC_DBG,
+ "Release plane: %d device_addr = %#lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ }
+
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+ buffer_info.response_required = false;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES
+ && b->m.planes[extra_idx].m.userptr)
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ else
+ buffer_info.extradata_addr = 0;
+
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_release_buffers failed\n");
+ break;
+ default:
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+exit:
+ return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
+ return -EINVAL;
+ }
+
+ mutex_lock(&q->lock);
+ rc = vb2_qbuf(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
+
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
+ return -EINVAL;
+ }
+ mutex_lock(&q->lock);
+ rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+
+ if (!inst || !b) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
+ return -EINVAL;
+ }
+
+ mutex_lock(&q->lock);
+ rc = vb2_reqbufs(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
+
+ if (rc)
+ dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ struct hfi_device *hdev;
+ int rc = 0, i = 0, stride = 0, scanlines = 0;
+ unsigned int *plane_sizes = NULL, extra_idx = 0;
+ struct hal_buffer_requirements *bufreq;
+
+ if (!inst || !f || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "Getting buffer requirements failed: %d\n",
+ rc);
+ return rc;
+ }
+
+ hdev = inst->core->device;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+ else
+ return -ENOTSUPP;
+
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ if (inst->in_reconfig) {
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.height[CAPTURE_PORT] = inst->reconfig_height;
+ inst->prop.width[CAPTURE_PORT] = inst->reconfig_width;
+ inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
+ inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
+ } else {
+ inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
+ inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
+ }
+
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: unsupported session\n", __func__);
+ goto exit;
+ }
+ }
+
+ f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+ f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+ stride = inst->prop.width[CAPTURE_PORT];
+ scanlines = inst->prop.height[CAPTURE_PORT];
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed : Buffer requirements\n", __func__);
+ goto exit;
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ plane_sizes = &inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
+ for (i = 0; i < fmt->num_planes; ++i) {
+ if (!plane_sizes[i]) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ get_frame_size(inst, fmt, f->type, i);
+ plane_sizes[i] = f->fmt.pix_mp.plane_fmt[i].
+ sizeimage;
+ } else
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ plane_sizes[i];
+ }
+ } else {
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12_UBWC:
+ call_hfi_op(hdev, get_stride_scanline,
+ COLOR_FMT_NV12,
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ &stride, &scanlines);
+ break;
+ default:
+ dprintk(VIDC_WARN, "Color format not recognized\n");
+ break;
+ }
+
+ bufreq = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ bufreq ? bufreq->buffer_size : 0;
+
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ bufreq ? bufreq->buffer_size : 0;
+ }
+
+ for (i = 0; i < fmt->num_planes; ++i)
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ if (stride && scanlines) {
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)stride;
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)scanlines;
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)inst->prop.width[CAPTURE_PORT];
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)inst->prop.height[CAPTURE_PORT];
+ }
+
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+ f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ f->fmt.pix_mp.height = inst->prop.height[OUTPUT_PORT];
+ f->fmt.pix_mp.width = inst->prop.width[OUTPUT_PORT];
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)inst->prop.width[OUTPUT_PORT];
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)inst->prop.height[OUTPUT_PORT];
+ }
+ }
+exit:
+ return rc;
+}
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u64 us_per_frame = 0;
+ int rc = 0, fps = 0;
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator *
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
+ break;
+ }
+ }
+
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ fps = USEC_PER_SEC;
+ do_div(fps, us_per_frame);
+
+ if (fps % 15 == 14 || fps % 24 == 23)
+ fps = fps + 1;
+ else if (fps % 24 == 1 || fps % 15 == 1)
+ fps = fps - 1;
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
+ msm_dcvs_init_load(inst);
+ msm_comm_scale_clocks_and_bus(inst);
+ }
+exit:
+ return rc;
+}
+
+static int set_buffer_size(struct msm_vidc_inst *inst,
+ u32 buffer_size, enum hal_buffer buffer_type)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct hal_buffer_size_actual buffer_size_actual;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ dprintk(VIDC_DBG,
+ "Set actual buffer size = %d for buffer type %d to fw\n",
+ buffer_size, buffer_type);
+
+ buffer_size_actual.buffer_type = buffer_type;
+ buffer_size_actual.buffer_size = buffer_size;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, HAL_PARAM_BUFFER_SIZE_ACTUAL,
+ &buffer_size_actual);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "%s - failed to set actual buffer size %u on firmware\n",
+ __func__, buffer_size);
+ return rc;
+}
+
+static int update_output_buffer_size(struct msm_vidc_inst *inst,
+ struct v4l2_format *f, struct msm_vidc_format *fmt)
+{
+ int rc = 0, i = 0;
+ struct hal_buffer_requirements *bufreq;
+
+ if (!inst || !f || !fmt)
+ return -EINVAL;
+
+ /*
+ * Compare set buffer size and update to firmware if it's bigger
+ * then firmware returned buffer size.
+ */
+ for (i = 0; i < fmt->num_planes; ++i) {
+ enum hal_buffer type = msm_comm_get_hal_output_buffer(inst);
+
+ if (EXTRADATA_IDX(fmt->num_planes) &&
+ i == EXTRADATA_IDX(fmt->num_planes)) {
+ type = HAL_BUFFER_EXTRADATA_OUTPUT;
+ }
+
+ bufreq = get_buff_req_buffer(inst, type);
+ if (!bufreq)
+ goto exit;
+
+ if (f->fmt.pix_mp.plane_fmt[i].sizeimage >
+ bufreq->buffer_size) {
+ rc = set_buffer_size(inst,
+ f->fmt.pix_mp.plane_fmt[i].sizeimage, type);
+ if (rc)
+ goto exit;
+ }
+ }
+
+ /* Query buffer requirements from firmware */
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to get buf req, %d\n", rc);
+
+ /* Read back updated firmware size */
+ for (i = 0; i < fmt->num_planes; ++i) {
+ enum hal_buffer type = msm_comm_get_hal_output_buffer(inst);
+
+ if (EXTRADATA_IDX(fmt->num_planes) &&
+ i == EXTRADATA_IDX(fmt->num_planes)) {
+ type = HAL_BUFFER_EXTRADATA_OUTPUT;
+ }
+
+ bufreq = get_buff_req_buffer(inst, type);
+ f->fmt.pix_mp.plane_fmt[i].sizeimage = bufreq ?
+ bufreq->buffer_size : 0;
+ dprintk(VIDC_DBG,
+ "updated buffer size for plane[%d] = %d\n",
+ i, f->fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+exit:
+ return rc;
+}
+
+static int set_default_properties(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev;
+ struct v4l2_control ctrl = {0};
+ enum hal_default_properties defaults;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ defaults = call_hfi_op(hdev, get_default_properties,
+ hdev->hfi_device_data);
+
+ if (defaults & HAL_VIDEO_DYNAMIC_BUF_MODE) {
+ dprintk(VIDC_DBG, "Enable dynamic buffer mode\n");
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT;
+ ctrl.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC;
+ rc = v4l2_s_ctrl(NULL, &inst->ctrl_handler, &ctrl);
+ if (rc)
+ dprintk(VIDC_ERR, "set alloc_mode failed\n");
+ }
+
+ if (defaults & HAL_VIDEO_CONTINUE_DATA_TRANSFER) {
+ dprintk(VIDC_DBG, "Enable continue_data_transfer\n");
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ ctrl.value = true;
+ rc = v4l2_s_ctrl(NULL, &inst->ctrl_handler, &ctrl);
+ if (rc)
+ dprintk(VIDC_ERR, "set cont_data_transfer failed\n");
+ }
+
+ return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ struct msm_vidc_format *fmt = NULL;
+ struct hal_frame_size frame_sz;
+ int rc = 0;
+ int ret = 0;
+ int i;
+ int max_input_size = 0;
+
+ if (!inst || !f) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (!fmt || fmt->type != CAPTURE_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
+ f->fmt.pix_mp.pixelformat);
+ }
+
+ inst->fmts[fmt->type] = fmt;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
+ msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
+ f->fmt.pix_mp.pixelformat);
+ msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2,
+ f->fmt.pix_mp.pixelformat);
+ dprintk(VIDC_DBG,
+ "buffer type = %d width = %d, height = %d\n",
+ frame_sz.buffer_type, frame_sz.width,
+ frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ }
+
+ ret = ret || msm_comm_try_get_bufreqs(inst);
+ if (ret) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ get_frame_size(inst, fmt, f->type, i);
+ }
+ } else {
+ rc = update_output_buffer_size(inst, f, fmt);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s - failed to update buffer size: %d\n",
+ __func__, rc);
+ goto err_invalid_fmt;
+ }
+ }
+
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ }
+
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_invalid_fmt;
+ }
+
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats),
+ f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (!fmt || fmt->type != OUTPUT_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to initialize instance\n");
+ goto err_invalid_fmt;
+ }
+
+ if (!(get_hal_codec_type(fmt->fourcc) &
+ inst->core->dec_codec_supported)) {
+ dprintk(VIDC_ERR,
+ "Codec(%#x) is not present in the supported codecs list(%#x)\n",
+ get_hal_codec_type(fmt->fourcc),
+ inst->core->dec_codec_supported);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+
+ inst->fmts[fmt->type] = fmt;
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->prop.width[OUTPUT_PORT];
+ frame_sz.height = inst->prop.height[OUTPUT_PORT];
+ dprintk(VIDC_DBG,
+ "buffer type = %d width = %d, height = %d\n",
+ frame_sz.buffer_type, frame_sz.width,
+ frame_sz.height);
+ msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+
+ max_input_size = get_frame_size(inst, fmt, f->type, 0);
+ if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+ !f->fmt.pix_mp.plane_fmt[0].sizeimage) {
+ f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+ }
+
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ set_default_properties(inst);
+ }
+err_invalid_fmt:
+ return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
+ cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ dprintk(VIDC_DBG, "No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int set_display_hold_count(struct msm_vidc_inst *inst,
+ unsigned int display_count)
+{
+ int rc = 0;
+ struct hal_buffer_display_hold_count_actual display;
+ struct hfi_device *hdev;
+
+ hdev = inst->core->device;
+
+ display.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
+ display.hold_count = display_count;
+
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session,
+ HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL,
+ &display);
+ if (rc)
+ dprintk(VIDC_ERR, "failed to set display hold count %d\n", rc);
+
+ return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_buffer_requirements *bufreq;
+ int extra_idx = 0;
+ struct hfi_device *hdev;
+ struct hal_buffer_count_actual new_buf_count;
+ enum hal_property property_id;
+ struct context_bank_info *cb;
+
+ if (!q || !num_buffers || !num_planes
+ || !sizes || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
+ q, num_buffers, num_planes);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ cb = msm_smem_get_context_bank(inst->mem_client, false, HAL_BUFFER_INPUT);
+ if (!cb) {
+ dprintk(VIDC_ERR,"Failed to find context bank for input buffer\n");
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = get_frame_size(inst,
+ inst->fmts[OUTPUT_PORT], q->type, i);
+ alloc_ctxs[i] = cb->alloc_ctx;
+ }
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, property_id, &new_buf_count);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to set new buffer count(%d) on FW, err: %d\n",
+ new_buf_count.buffer_count_actual, rc);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+ *num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+
+ bufreq = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+ if (!bufreq) {
+ dprintk(VIDC_ERR,
+ "No buffer requirement for buffer type %x\n",
+ HAL_BUFFER_OUTPUT);
+ rc = -EINVAL;
+ break;
+ }
+
+ *num_buffers = max(*num_buffers, bufreq->buffer_count_min);
+ if (*num_buffers != bufreq->buffer_count_actual) {
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, property_id, &new_buf_count);
+
+ set_display_hold_count(inst,
+ *num_buffers - bufreq->buffer_count_actual);
+ }
+
+ if (*num_buffers != bufreq->buffer_count_actual) {
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to get buf req, %d\n", rc);
+ break;
+ }
+ }
+ dprintk(VIDC_DBG, "count = %d, size = %d, alignment = %d\n",
+ inst->buff_req.buffer[1].buffer_count_actual,
+ inst->buff_req.buffer[1].buffer_size,
+ inst->buff_req.buffer[1].buffer_alignment);
+ cb = msm_smem_get_context_bank(inst->mem_client, false,
+ msm_comm_get_hal_output_buffer(inst));
+ if (!cb) {
+ dprintk(VIDC_ERR,"Failed to find context bank for output buffer\n");
+ rc = -EINVAL;
+ break;
+ }
+ sizes[0] = bufreq->buffer_size;
+ alloc_ctxs[0] = cb->alloc_ctx;
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ cb = msm_smem_get_context_bank(inst->mem_client, false,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (!cb) {
+ dprintk(VIDC_ERR,"Failed to find context bank for extradata output buffer\n");
+ rc = -EINVAL;
+ break;
+ }
+ alloc_ctxs[extra_idx] = cb->alloc_ctx;
+ if (bufreq) {
+ sizes[extra_idx] = bufreq->buffer_size;
+ } else {
+ *num_planes = 1;
+ sizes[extra_idx] = 0;
+ }
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_vdec_buf_init(struct vb2_buffer *vb)
+{
+ int rc = 0, i = 0;
+ struct vb2_queue *q = vb->vb2_queue;
+ struct msm_vidc_inst *inst = q->drv_priv;
+ struct buffer_info* binfo = NULL;
+ struct vidc_buffer_addr_info buffer_info;
+ enum hal_buffer buffer_type = HAL_BUFFER_INPUT;
+ struct dma_buf* dbuf;
+ struct hfi_device *hdev;
+
+ dprintk(VIDC_DBG, "msm_vdec_buf_init \n");
+ if (q->memory == V4L2_MEMORY_USERPTR ||
+ q->memory == V4L2_MEMORY_DMABUF) {
+ dprintk(VIDC_DBG,
+ "Ignore buf init for userptr & DMABUF modes");
+ return rc;
+ }
+ if (!inst) {
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ buffer_type = HAL_BUFFER_INPUT;
+ else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ buffer_type = HAL_BUFFER_OUTPUT;
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ if (vb->vb2_queue->mem_ops->get_dmabuf != NULL) {
+ dbuf = vb->vb2_queue->mem_ops->get_dmabuf(
+ vb->planes[i].mem_priv, 0);
+ }
+ else {
+ dprintk(VIDC_ERR, "get_dmabuf is not supported \n");
+ rc = -EINVAL;
+ goto free_binfo;
+ }
+ binfo->handle[i] = msm_smem_map_dma_buf(
+ inst->mem_client, dbuf, buffer_type);
+ binfo->mapped[i] = true;
+ binfo->device_addr[i] = binfo->handle[i]->device_addr;
+ binfo->size[i] = vb->v4l2_planes[i].length;
+ dprintk(VIDC_DBG, "%s: device_addr 0x %pa, index %d, plane %d, size %d",
+ __func__, &binfo->device_addr[i], vb->v4l2_buf.index, i, binfo->size[i]);
+ }
+ binfo->num_planes = vb->num_planes;
+ binfo->memory = q->memory;
+ binfo->v4l2_index = vb->v4l2_buf.index;
+ binfo->type = q->type;
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_add_tail(&binfo->list, &inst->registeredbufs.list);
+ mutex_unlock(&inst->registeredbufs.lock);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ //set buffer to FW, TODO move to dymaic buf mode
+ buffer_info.buffer_size = vb->v4l2_planes[0].length;
+ buffer_info.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = binfo->device_addr[0];
+ buffer_info.extradata_addr = 0;
+ buffer_info.extradata_size = 0;
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
+
+ }
+
+ return rc;
+free_binfo:
+ kfree(binfo);
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct vb2_buf_entry *temp;
+ struct hfi_device *hdev;
+ struct list_head *ptr, *next;
+
+ hdev = inst->core->device;
+ inst->in_reconfig = false;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY)
+ rc = msm_vidc_check_scaling_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+ return -EINVAL;
+ }
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_set_persist_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set persist buffers: %d\n", rc);
+ goto fail_start;
+ }
+
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ rc = msm_comm_set_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set output buffers: %d\n", rc);
+ goto fail_start;
+ }
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto fail_start;
+ }
+ msm_dcvs_init_load(inst);
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ rc = msm_comm_queue_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to queue output buffers: %d\n", rc);
+ goto fail_start;
+ }
+ }
+ mutex_lock(&inst->pendingq.lock);
+ list_for_each_safe(ptr, next, &inst->pendingq.list) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ mutex_unlock(&inst->pendingq.lock);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ return rc;
+}
+
+static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ struct hfi_device *hdev;
+ if (!q || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG,
+ "Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static void msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ return /*-EINVAL*/;
+ }
+ inst = q->drv_priv;
+ dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+ rc = stop_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+ rc = stop_streaming(inst);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ /*return rc;*/
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+
+ if (!dec || !inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ core = inst->core;
+ switch (dec->cmd) {
+ case V4L2_DEC_QCOM_CMD_FLUSH:
+ if (core->state != VIDC_CORE_INVALID &&
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_kill_session(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to recover from session_error: %d\n",
+ rc);
+ }
+ rc = msm_comm_flush(inst, dec->flags);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to flush buffers: %d\n", rc);
+ }
+ break;
+ case V4L2_DEC_CMD_STOP:
+ if (core->state != VIDC_CORE_INVALID &&
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_kill_session(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to recover from session_error: %d\n",
+ rc);
+ }
+ rc = msm_comm_release_scratch_buffers(inst, false);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to release scratch buffers: %d\n", rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ pr_err("Failed to release persist buffers: %d\n", rc);
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core %p in bad state, Sending CLOSE event\n",
+ core);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
+ goto exit;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ /* Clients rely on this event for joining poll thread.
+ * This event should be returned even if firmware has
+ * failed to respond */
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Unknown Decoder Command\n");
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to exec decoder cmd %d\n", dec->cmd);
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+ .queue_setup = msm_vdec_queue_setup,
+ .buf_init = msm_vdec_buf_init,
+ .start_streaming = msm_vdec_start_streaming,
+ .buf_queue = msm_vdec_buf_queue,
+ .stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+ return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[OUTPUT_PORT] = &vdec_formats[2];
+ inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
+ inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+ inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+ inst->capability.height.max = DEFAULT_HEIGHT;
+ inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+ inst->capability.width.max = DEFAULT_WIDTH;
+ inst->capability.buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->capability.buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->capability.secure_output2_threshold.min = 0;
+ inst->capability.secure_output2_threshold.max = 0;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->prop.fps = 30;
+ return rc;
+}
+
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+ switch (val) {
+ case V4L2_MPEG_VIDC_VIDEO_STATIC:
+ return HAL_BUFFER_MODE_STATIC;
+ case V4L2_MPEG_VIDC_VIDEO_RING:
+ return HAL_BUFFER_MODE_RING;
+ case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+ return HAL_BUFFER_MODE_DYNAMIC;
+ default:
+ dprintk(VIDC_ERR, "%s: invalid buf type: %d\n", __func__, val);
+ }
+ return 0;
+}
+
+static int check_tz_dynamic_buffer_support(void)
+{
+ int rc = 0;
+ int version = qcom_scm_get_feat_version(TZ_DYNAMIC_BUFFER_FEATURE_ID);
+
+ /*
+ * if the version is < 1.1.0 then dynamic buffer allocation is
+ * not supported
+ */
+ if (version < TZ_FEATURE_VERSION(1, 1, 0)) {
+ dprintk(VIDC_DBG,
+ "Dynamic buffer mode not supported, tz version is : %u vs required : %u\n",
+ version, TZ_FEATURE_VERSION(1, 1, 0));
+ rc = -ENOTSUPP;
+ }
+
+ return rc;
+}
+
+static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct hal_profile_level profile_level;
+ union hal_get_property hprop;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ dprintk(VIDC_DBG, "%s ctrl->id:%x\n", __func__, ctrl->id);
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+ rc = msm_comm_try_get_prop(inst,
+ HAL_PARAM_PROFILE_LEVEL_CURRENT,
+ &hprop);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s Error rc:%d\n", __func__, rc);
+ return rc;
+ }
+ profile_level = hprop.profile_level;
+ ctrl->val = profile_level.profile;
+ dprintk(VIDC_DBG, "%s: PROFILE ctrl->id:%x ctrl->val:%d\n",
+ __func__, ctrl->id, ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+ rc = msm_comm_try_get_prop(inst,
+ HAL_PARAM_PROFILE_LEVEL_CURRENT,
+ &hprop);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s Error rc:%d\n", __func__, rc);
+ return rc;
+ }
+ profile_level = hprop.profile_level;
+ ctrl->val = profile_level.level;
+ dprintk(VIDC_DBG, "%s: LEVEL ctrl->id:%x ctrl->val:%d\n",
+ __func__, ctrl->id, ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD:
+ if (!(inst->flags & VIDC_SECURE) ||
+ !inst->capability.secure_output2_threshold.max) {
+ dprintk(VIDC_ERR, "%s id:%x invalid configuration\n",
+ __func__, ctrl->id);
+ rc = -EINVAL;
+ break;
+ }
+ dprintk(VIDC_DBG,
+ "Secure Scaling Threshold is : %d",
+ inst->capability.secure_output2_threshold.max);
+ ctrl->val = inst->capability.secure_output2_threshold.max;
+ break;
+ default:
+ dprintk(VIDC_DBG, "%s id:%x not supported\n",
+ __func__, ctrl->id);
+ break;
+ }
+ return rc;
+}
+
+static int vdec_v4l2_to_hal(int id, int value)
+{
+ switch (id) {
+ /* H264 */
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ return HAL_H264_PROFILE_BASELINE;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ return HAL_H264_PROFILE_CONSTRAINED_BASE;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ return HAL_H264_PROFILE_MAIN;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ return HAL_H264_PROFILE_EXTENDED;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ return HAL_H264_PROFILE_HIGH;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+ return HAL_H264_PROFILE_HIGH10;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+ return HAL_H264_PROFILE_HIGH422;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+ return HAL_H264_PROFILE_HIGH444;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return HAL_H264_LEVEL_1;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return HAL_H264_LEVEL_1b;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return HAL_H264_LEVEL_11;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return HAL_H264_LEVEL_12;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return HAL_H264_LEVEL_13;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return HAL_H264_LEVEL_2;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return HAL_H264_LEVEL_21;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return HAL_H264_LEVEL_22;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return HAL_H264_LEVEL_3;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return HAL_H264_LEVEL_31;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return HAL_H264_LEVEL_32;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return HAL_H264_LEVEL_4;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return HAL_H264_LEVEL_41;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return HAL_H264_LEVEL_42;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return HAL_H264_LEVEL_5;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ return HAL_H264_LEVEL_51;
+ default:
+ goto unknown_value;
+ }
+ }
+unknown_value:
+ dprintk(VIDC_WARN, "Unknown control (%x, %d)", id, value);
+ return -EINVAL;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+ struct v4l2_ctrl **cluster, int ncontrols)
+{
+ int c;
+ for (c = 0; c < ncontrols; ++c)
+ if (cluster[c]->id == id)
+ return cluster[c];
+ return NULL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ struct hal_nal_stream_format_supported stream_format;
+ struct hal_enable_picture enable_picture;
+ struct hal_enable hal_property;
+ enum hal_property property_id = 0;
+ u32 property_val = 0;
+ void *pdata = NULL;
+ struct hfi_device *hdev;
+ struct hal_extradata_enable extra;
+ struct hal_buffer_alloc_mode alloc_mode;
+ struct hal_multi_stream multi_stream;
+ struct hfi_scs_threshold scs_threshold;
+ struct hal_mvc_buffer_layout layout;
+ struct v4l2_ctrl *temp_ctrl = NULL;
+ struct hal_profile_level profile_level;
+ struct hal_frame_size frame_sz;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ rc = is_ctrl_valid_for_codec(inst, ctrl);
+ if (rc)
+ return rc;
+
+ /* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+ struct v4l2_ctrl *__temp; \
+ __temp = get_ctrl_from_cluster( \
+ __ctrl_id, \
+ ctrl->cluster, ctrl->ncontrols); \
+ if (!__temp) { \
+ dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+ #__ctrl_id, __ctrl_id); \
+ /* Clusters are hardcoded, if we can't find */ \
+ /* something then things are massively screwed up */ \
+ BUG_ON(1); \
+ } \
+ __temp; \
+ })
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ property_id =
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_supported =
+ (0x00000001 << ctrl->val);
+ pdata = &stream_format;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+ property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+ property_val = ctrl->val;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+ property_id =
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ enable_picture.picture_type = ctrl->val;
+ pdata = &enable_picture;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+ property_id =
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+ property_id =
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+ property_id = HAL_PARAM_DIVX_FORMAT;
+ property_val = ctrl->val;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+ property_id =
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+ property_id =
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE:
+ inst->flags &= ~VIDC_THUMBNAIL;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE:
+ inst->flags |= VIDC_THUMBNAIL;
+ break;
+ }
+
+ property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+ inst->flags |= VIDC_SECURE;
+ dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
+ !!(inst->flags & VIDC_SECURE));
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ property_id = HAL_PARAM_INDEX_EXTRADATA;
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+ extra.enable = 1;
+ pdata = &extra;
+ break;
+ case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+ inst->flags &= ~VIDC_TURBO;
+ break;
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+ inst->flags |= VIDC_TURBO;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+ if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+ rc = -ENOTSUPP;
+ break;
+ }
+ property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+ alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+ inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+ pdata = &alloc_mode;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
+ property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+ property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+
+ if (!(alloc_mode.buffer_mode &
+ inst->capability.buffer_mode[CAPTURE_PORT])) {
+ dprintk(VIDC_DBG,
+ "buffer mode[%d] not supported for Capture Port\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ if (alloc_mode.buffer_mode == HAL_BUFFER_MODE_DYNAMIC &&
+ (inst->flags & VIDC_SECURE) &&
+ check_tz_dynamic_buffer_support()) {
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &alloc_mode;
+ inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+ if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
+ dprintk(VIDC_ERR, "Downscaling not supported: %#x\n",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+ multi_stream.enable = true;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed : Enabling OUTPUT port : %d\n",
+ rc);
+ break;
+ }
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+ multi_stream.enable = false;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed:Disabling OUTPUT2 port : %d\n",
+ rc);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+ multi_stream.enable = true;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed :Enabling OUTPUT2 port : %d\n",
+ rc);
+ break;
+ }
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+ multi_stream.enable = false;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed disabling OUTPUT port : %d\n",
+ rc);
+ break;
+ }
+
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
+ pdata = &frame_sz;
+ dprintk(VIDC_DBG,
+ "buffer type = %d width = %d, height = %d\n",
+ frame_sz.buffer_type, frame_sz.width,
+ frame_sz.height);
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_FRAME_SIZE, pdata);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed setting OUTPUT2 size : %d\n",
+ rc);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Failed : Unsupported multi stream setting\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD:
+ property_id = HAL_PARAM_VDEC_SCS_THRESHOLD;
+ scs_threshold.threshold_value = ctrl->val;
+ pdata = &scs_threshold;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+ property_id = HAL_PARAM_MVC_BUFFER_LAYOUT;
+ layout.layout_type = msm_comm_get_hal_buffer_layout(ctrl->val);
+ layout.bright_view_first = 0;
+ layout.ngap = 0;
+ pdata = &layout;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
+ property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
+ property_val = ctrl->val;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = vdec_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = vdec_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = vdec_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = vdec_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT:
+ inst->capability.buffer_size_limit = ctrl->val;
+ dprintk(VIDC_DBG,
+ "Limiting input buffer size to :%u\n", ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2:
+ property_id = HAL_PARAM_VDEC_NON_SECURE_OUTPUT2;
+ hal_property.enable = ctrl->val;
+ dprintk(VIDC_DBG, "%s non_secure output2\n",
+ ctrl->val ? "Enabling" : "Disabling");
+ pdata = &hal_property;
+ break;
+ default:
+ break;
+ }
+#undef TRY_GET_CTRL
+
+ if (!rc && property_id) {
+ dprintk(VIDC_DBG,
+ "Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
+ property_id, ctrl->id, ctrl->val);
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, property_id, pdata);
+ }
+
+ return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int rc = 0, c = 0;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto failed_open_done;
+ }
+
+ for (c = 0; c < ctrl->ncontrols; ++c) {
+ if (ctrl->cluster[c]->is_new) {
+ rc = try_set_ctrl(inst, ctrl->cluster[c]);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed setting %x\n",
+ ctrl->cluster[c]->id);
+ break;
+ }
+ }
+ }
+
+failed_open_done:
+ if (rc)
+ dprintk(VIDC_ERR, "Failed setting control: %x (%s)",
+ ctrl->id, v4l2_ctrl_get_name(ctrl->id));
+ return rc;
+}
+
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int rc = 0, c = 0;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto failed_open_done;
+ }
+ for (c = 0; c < master->ncontrols; ++c) {
+ int d = 0;
+ for (d = 0; d < NUM_CTRLS; ++d) {
+ if (master->cluster[c]->id == inst->ctrls[d]->id &&
+ inst->ctrls[d]->flags &
+ V4L2_CTRL_FLAG_VOLATILE) {
+ rc = try_get_ctrl(inst, master->cluster[c]);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed getting %x\n",
+ master->cluster[c]->id);
+ return rc;
+ }
+ break;
+ }
+ }
+ }
+ return rc;
+
+failed_open_done:
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to get hal property\n");
+ return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+ .s_ctrl = msm_vdec_op_s_ctrl,
+ .g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+ return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl);
+}
+int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+ int *size)
+{
+ int c = 0, sz = 0;
+ struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+ NUM_CTRLS, GFP_KERNEL);
+
+ if (!size || !cluster || !inst)
+ return NULL;
+
+ for (c = 0; c < NUM_CTRLS; c++)
+ cluster[sz++] = inst->ctrls[c];
+
+ *size = sz;
+ return cluster;
+}
+
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
+ int ret_val = 0;
+ int cluster_size = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS,
+ GFP_KERNEL);
+ if (!inst->ctrls) {
+ dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+
+ if (ret_val) {
+ dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ struct v4l2_ctrl *ctrl = NULL;
+ if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
+ /*add private control*/
+ ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_vdec_ctrls[idx].id;
+ /* ctrl_cfg.is_private =
+ * msm_vdec_ctrls[idx].is_private;
+ * ctrl_cfg.is_volatile =
+ * msm_vdec_ctrls[idx].is_volatile;*/
+ ctrl_cfg.max = msm_vdec_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_vdec_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_vdec_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_vdec_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_vdec_ctrl_ops;
+ ctrl_cfg.step = msm_vdec_ctrls[idx].step;
+ ctrl_cfg.type = msm_vdec_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
+
+ ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ ctrl = v4l2_ctrl_new_std_menu(
+ &inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].menu_skip_mask,
+ msm_vdec_ctrls[idx].default_value);
+ } else {
+ ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].minimum,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].step,
+ msm_vdec_ctrls[idx].default_value);
+ }
+ }
+
+ if (!ctrl) {
+ dprintk(VIDC_ERR, "%s - invalid ctrl\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (msm_vdec_ctrls[idx].id) {
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD:
+ ctrl->flags |= msm_vdec_ctrls[idx].flags;
+ break;
+ }
+
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val) {
+ dprintk(VIDC_ERR,
+ "Error adding ctrl (%s) to ctrl handle, %d\n",
+ msm_vdec_ctrls[idx].name,
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ inst->ctrls[idx] = ctrl;
+ }
+
+ /* Construct a super cluster of all controls */
+ inst->cluster = get_super_cluster(inst, &cluster_size);
+ if (!inst->cluster || !cluster_size) {
+ dprintk(VIDC_WARN,
+ "Failed to setup super cluster\n");
+ return -EINVAL;
+ }
+
+ v4l2_ctrl_cluster(cluster_size, inst->cluster);
+
+ return ret_val;
+}
+
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ kfree(inst->ctrls);
+ kfree(inst->cluster);
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.h b/drivers/media/platform/msm/vidc/msm_vdec.h
new file mode 100644
index 000000000000..c7f842700161
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vdec.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2012, 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.
+ *
+ */
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
new file mode 100644
index 000000000000..4db8f9921440
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -0,0 +1,3771 @@
+/* Copyright (c) 2012-2015, 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/slab.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_CAPTURE_BUFFERS 4
+#define MIN_BIT_RATE 32000
+#define MAX_BIT_RATE 160000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define DEFAULT_FRAME_RATE 15
+#define MAX_SLICE_BYTE_SIZE 1024
+#define MIN_SLICE_BYTE_SIZE 1024
+#define MAX_SLICE_MB_SIZE 300
+#define I_FRAME_QP 26
+#define P_FRAME_QP 28
+#define B_FRAME_QP 30
+#define MAX_INTRA_REFRESH_MBS 300
+#define MAX_NUM_B_FRAMES 4
+#define MAX_LTR_FRAME_COUNT 10
+
+#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
+#define BITSTREAM_RESTRICT_ENABLED \
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED
+#define BITSTREAM_RESTRICT_DISABLED \
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED
+#define MIN_TIME_RESOLUTION 1
+#define MAX_TIME_RESOLUTION 0xFFFFFF
+#define DEFAULT_TIME_RESOLUTION 0x7530
+
+/*
+ * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
+ * coeffs are converted to s4.9 format (e.g. -22 converted to ((1 << 13) - 22)
+ * 3x3 transformation matrix coefficients in s4.9 fixed point format
+ */
+static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
+ 470, 8170, 8148, 0, 490, 50, 0, 34, 483
+};
+
+/* offset coefficients in s9 fixed point format */
+static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
+ 34, 0, 4
+};
+
+/* clamping value for Y/U/V([min,max] for Y/U/V) */
+static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
+ 16, 235, 16, 240, 16, 240
+};
+
+static const char *const mpeg_video_rate_control[] = {
+ "No Rate Control",
+ "VBR VFR",
+ "VBR CFR",
+ "CBR VFR",
+ "CBR CFR",
+ NULL
+};
+
+static const char *const mpeg_video_rotation[] = {
+ "No Rotation",
+ "90 Degree Rotation",
+ "180 Degree Rotation",
+ "270 Degree Rotation",
+ NULL
+};
+
+static const char *const h264_video_entropy_cabac_model[] = {
+ "Model 0",
+ "Model 1",
+ "Model 2",
+ NULL
+};
+
+static const char *const h263_level[] = {
+ "1.0",
+ "2.0",
+ "3.0",
+ "4.0",
+ "4.5",
+ "5.0",
+ "6.0",
+ "7.0",
+};
+
+static const char *const h263_profile[] = {
+ "Baseline",
+ "H320 Coding",
+ "Backward Compatible",
+ "ISWV2",
+ "ISWV3",
+ "High Compression",
+ "Internet",
+ "Interlace",
+ "High Latency",
+};
+
+static const char *const hevc_tier_level[] = {
+ "Main Tier Level 1",
+ "Main Tier Level 2",
+ "Main Tier Level 2.1",
+ "Main Tier Level 3",
+ "Main Tier Level 3.1",
+ "Main Tier Level 4",
+ "Main Tier Level 4.1",
+ "Main Tier Level 5",
+ "Main Tier Level 5.1",
+ "Main Tier Level 5.2",
+ "Main Tier Level 6",
+ "Main Tier Level 6.1",
+ "Main Tier Level 6.2",
+ "High Tier Level 1",
+ "High Tier Level 2",
+ "High Tier Level 2.1",
+ "High Tier Level 3",
+ "High Tier Level 3.1",
+ "High Tier Level 4",
+ "High Tier Level 4.1",
+ "High Tier Level 5",
+ "High Tier Level 5.1",
+ "High Tier Level 5.2",
+ "High Tier Level 6",
+ "High Tier Level 6.1",
+ "High Tier Level 6.2",
+};
+
+static const char *const hevc_profile[] = {
+ "Main",
+ "Main10",
+ "Main Still Pic",
+};
+
+static const char *const vp8_profile_level[] = {
+ "Unused",
+ "0.0",
+ "1.0",
+ "2.0",
+ "3.0",
+};
+
+static const char *const mpeg_video_vidc_extradata[] = {
+ "Extradata none",
+ "Extradata MB Quantization",
+ "Extradata Interlace Video",
+ "Extradata VC1 Framedisp",
+ "Extradata VC1 Seqdisp",
+ "Extradata timestamp",
+ "Extradata S3D Frame Packing",
+ "Extradata Frame Rate",
+ "Extradata Panscan Window",
+ "Extradata Recovery point SEI",
+ "Extradata Closed Caption UD",
+ "Extradata AFD UD",
+ "Extradata Multislice info",
+ "Extradata number of concealed MB",
+ "Extradata metadata filler",
+ "Extradata input crop",
+ "Extradata digital zoom",
+ "Extradata aspect ratio",
+ "Extradata macroblock metadata",
+};
+
+static const char *const perf_level[] = {
+ "Nominal",
+ "Performance",
+ "Turbo"
+};
+
+static const char *const intra_refresh_modes[] = {
+ "None",
+ "Cyclic",
+ "Adaptive",
+ "Cyclic Adaptive",
+ "Random"
+};
+
+static const char *const timestamp_mode[] = {
+ "Honor",
+ "Ignore",
+};
+
+static struct msm_vidc_ctrl msm_venc_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
+ .name = "IDR Period",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = INT_MAX,
+ .default_value = DEFAULT_FRAME_RATE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
+ .name = "Intra Period for P frames",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 2*DEFAULT_FRAME_RATE-1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
+ .name = "Intra Period for B frames",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
+ .name = "Request I Frame",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .default_value = 0,
+ .step = 0,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
+ .name = "Video Framerate and Bitrate Control",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
+ ),
+ .qmenu = mpeg_video_rate_control,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ .name = "Bitrate Control",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ ),
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ .name = "Bit Rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_BIT_RATE,
+ .maximum = MAX_BIT_RATE,
+ .default_value = DEFAULT_BIT_RATE,
+ .step = BIT_RATE_STEP,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ .name = "Peak Bit Rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_BIT_RATE,
+ .maximum = MAX_BIT_RATE,
+ .default_value = DEFAULT_BIT_RATE,
+ .step = BIT_RATE_STEP,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ .name = "Entropy Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+ (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+ .name = "CABAC Model",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
+ ),
+ .qmenu = h264_video_entropy_cabac_model,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .name = "MPEG4 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum = CODING,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .name = "MPEG4 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .name = "H264 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .name = "H264 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .step = 0,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ .name = "H263 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+ ),
+ .qmenu = h263_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ .name = "H263 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+ ),
+ .qmenu = h263_level,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ .name = "VP8 Profile Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+ ),
+ .qmenu = vp8_profile_level,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ .name = "HEVC Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC)
+ ),
+ .qmenu = hevc_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ .name = "HEVC Tier and Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1)
+ ),
+ .qmenu = hevc_tier_level,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+ .name = "Rotation",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
+ ),
+ .qmenu = mpeg_video_rotation,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ .name = "I Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = I_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ .name = "P Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = P_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ .name = "B Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = B_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ .name = "H264 Minimum QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = 1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ .name = "H264 Maximum QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = 51,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP,
+ .name = "VP8 Minimum QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 128,
+ .default_value = 1,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP,
+ .name = "VP8 Maximum QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 128,
+ .default_value = 128,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ .name = "Slice Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB,
+ .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .step = 1,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+ .name = "Slice Byte Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_SLICE_BYTE_SIZE,
+ .maximum = MAX_SLICE_BYTE_SIZE,
+ .default_value = MIN_SLICE_BYTE_SIZE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ .name = "Slice MB Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = MAX_SLICE_MB_SIZE,
+ .default_value = 1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
+ .name = "Slice GOB",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = MAX_SLICE_MB_SIZE,
+ .default_value = 1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
+ .name = "Slice delivery mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
+ .name = "Intra Refresh Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
+ ),
+ .qmenu = intra_refresh_modes,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
+ .name = "Intra Refresh AIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
+ .name = "Intra Refresh AIR REF",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
+ .name = "Intra Refresh CIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ .name = "H.264 Loop Filter Alpha Offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ .name = "H.264 Loop Filter Beta Offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ .name = "H.264 Loop Filter Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED,
+ .maximum = L_MODE,
+ .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED,
+ .step = 1,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
+ (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
+ (1 << L_MODE)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ .name = "Sequence Header Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+ .default_value =
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+ .step = 1,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+ (1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+ .name = "Secure mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .default_value = 0,
+ .step = 0,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+ .name = "Extradata Type",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .maximum = V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI,
+ .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI)
+ ),
+ .qmenu = mpeg_video_vidc_extradata,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO,
+ .name = "H264 VUI Timing Info",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER,
+ .name = "H264 AU Delimiter",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED,
+ .step = 1,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+ .name = "Encoder Performance Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+ .default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+ .qmenu = perf_level,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+ .name = "Intra Refresh CIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT,
+ .name = "H264 VUI Timing Info",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = BITSTREAM_RESTRICT_DISABLED,
+ .maximum = BITSTREAM_RESTRICT_ENABLED,
+ .default_value = BITSTREAM_RESTRICT_ENABLED,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY,
+ .name = "Preserve Text Qualty",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE,
+ .name = "Deinterlace for encoder",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION,
+ .name = "Vop time increment resolution",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_TIME_RESOLUTION,
+ .maximum = MAX_TIME_RESOLUTION,
+ .default_value = DEFAULT_TIME_RESOLUTION,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER,
+ .name = "Request Seq Header",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .default_value = 0,
+ .step = 0,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME,
+ .name = "H264 Use LTR",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (MAX_LTR_FRAME_COUNT - 1),
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT,
+ .name = "Ltr Count",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_LTR_FRAME_COUNT,
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE,
+ .name = "Ltr Mode",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME,
+ .name = "H264 Mark LTR",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (MAX_LTR_FRAME_COUNT - 1),
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS,
+ .name = "Set Hier P num layers",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 3,
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE,
+ .name = "Encoder Timestamp Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum =
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+ .maximum =
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE)),
+ .qmenu = timestamp_mode,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE,
+ .name = "VP8 Error Resilience mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED,
+ .default_value =
+ V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP,
+ .name = "Enable setting initial QP",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .minimum = 0,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME |
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME |
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME,
+ .default_value = 0,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP,
+ .name = "Iframe initial QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = 1,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP,
+ .name = "Pframe initial QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = 1,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP,
+ .name = "Bframe initial QP",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = 1,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE,
+ .name = "I-Frame X coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE,
+ .name = "I-Frame Y coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE,
+ .name = "P-Frame X coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE,
+ .name = "P-Frame Y coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE,
+ .name = "B-Frame X coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE,
+ .name = "B-Frame Y coordinate search range",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 4,
+ .maximum = 128,
+ .default_value = 4,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC,
+ .name = "Enable H264 SVC NAL",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE,
+ .name = "Set Encoder performance mode",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS,
+ .name = "Set Hier B num layers",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 3,
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
+ .name = "Set Hybrid Hier P mode",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 5,
+ .default_value = 0,
+ .step = 1,
+ .qmenu = NULL,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
+
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+ int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2;
+ return ALIGN(sz, SZ_4K);
+}
+
+static struct msm_vidc_format venc_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "UBWC YCbCr Semiplanar 4:2:0",
+ .description = "UBWC Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12_UBWC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12_ubwc,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "VP8",
+ .description = "VP8 compressed format",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "HEVC",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = OUTPUT_PORT,
+ },
+};
+
+static int msm_venc_queue_setup(struct vb2_queue *q,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_buffer_count_actual new_buf_count;
+ enum hal_property property_id;
+ struct hfi_device *hdev;
+ struct hal_buffer_requirements *buff_req;
+ struct v4l2_ctrl *ctrl = NULL;
+ u32 extradata = 0, extra_idx = 0;
+ struct hal_buffer_requirements *buff_req_buffer = NULL;
+
+ if (!q || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ return rc;
+ }
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to get buffer requirements: %d\n", rc);
+ return rc;
+ }
+
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ *num_planes = 1;
+
+ buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (buff_req) {
+ *num_buffers = buff_req->buffer_count_actual =
+ max(*num_buffers, buff_req->buffer_count_actual);
+ }
+
+ if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS ||
+ *num_buffers > VB2_MAX_FRAME) {
+ int temp = *num_buffers;
+
+ *num_buffers = clamp_val(*num_buffers,
+ MIN_NUM_CAPTURE_BUFFERS,
+ VB2_MAX_FRAME);
+ dprintk(VIDC_INFO,
+ "Changing buffer count on CAPTURE_MPLANE from %d to %d for best effort encoding\n",
+ temp, *num_buffers);
+ }
+
+ ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+ if (ctrl)
+ extradata = v4l2_ctrl_g_ctrl(ctrl);
+ if (extradata != V4L2_MPEG_VIDC_EXTRADATA_NONE)
+ *num_planes = *num_planes + 1;
+ inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
+
+ for (i = 0; i < *num_planes; i++) {
+ int extra_idx = EXTRADATA_IDX(*num_planes);
+
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->prop.height[CAPTURE_PORT],
+ inst->prop.width[CAPTURE_PORT]);
+
+ if (extra_idx && i == extra_idx &&
+ extra_idx < VIDEO_MAX_PLANES) {
+ buff_req_buffer = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (!buff_req_buffer) {
+ dprintk(VIDC_ERR,
+ "%s: failed - invalid buffer req\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sizes[i] = buff_req_buffer->buffer_size;
+ }
+ }
+
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ new_buf_count.buffer_count_actual +=
+ msm_dcvs_get_extra_buff_count(inst, false);
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ property_id, &new_buf_count);
+ if (!rc)
+ msm_dcvs_set_buff_req_handled(inst, false);
+
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = 1;
+
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
+ max(*num_buffers, inst->buff_req.buffer[0].
+ buffer_count_actual);
+
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+
+ ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+ if (ctrl)
+ extradata = v4l2_ctrl_g_ctrl(ctrl);
+ if (extradata == V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP)
+ *num_planes = *num_planes + 1;
+ inst->fmts[OUTPUT_PORT]->num_planes = *num_planes;
+ new_buf_count.buffer_count_actual +=
+ msm_dcvs_get_extra_buff_count(inst, true);
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ property_id, &new_buf_count);
+ if (!rc)
+ msm_dcvs_set_buff_req_handled(inst, true);
+
+ dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
+ inst->buff_req.buffer[0].buffer_size,
+ inst->buff_req.buffer[0].buffer_alignment,
+ inst->buff_req.buffer[0].buffer_count_actual);
+ sizes[0] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ 0, inst->prop.height[OUTPUT_PORT],
+ inst->prop.width[OUTPUT_PORT]);
+
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[OUTPUT_PORT]->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buff_req_buffer = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_INPUT);
+ if (!buff_req_buffer) {
+ dprintk(VIDC_ERR,
+ "%s: failed - invalid buffer req\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sizes[extra_idx] = buff_req_buffer->buffer_size;
+ }
+
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
+{
+ int num_enh_layers = 0;
+ u32 property_id = 0;
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_VP8 &&
+ inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264)
+ return 0;
+
+ num_enh_layers = layers ? : 0;
+ dprintk(VIDC_DBG, "%s Hier-P in firmware\n",
+ num_enh_layers ? "Enable" : "Disable");
+
+ hdev = inst->core->device;
+ property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id,
+ (void *)&num_enh_layers);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: failed with error = %d\n", __func__, rc);
+ }
+ return rc;
+}
+
+static int set_bitrate_for_each_layer(struct msm_vidc_inst *inst,
+ u32 num_enh_layers, u32 total_bitrate)
+{
+ u32 property_id = 0;
+ int i = 0, rc = 0;
+ struct hfi_device *hdev = NULL;
+ struct hal_bitrate bitrate;
+ int bitrate_table[3][4] = {
+ {50, 50, 0, 0},
+ {34, 33, 33, 0},
+ {25, 25, 25, 25}
+ };
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!num_enh_layers || num_enh_layers > ARRAY_SIZE(bitrate_table)) {
+ dprintk(VIDC_ERR, "%s - invalid number of enh layers: %d\n",
+ __func__, num_enh_layers);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ for (i = 0; !rc && i <= num_enh_layers; i++) {
+ property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+ bitrate.bit_rate = (u32)((total_bitrate *
+ bitrate_table[num_enh_layers - 1][i]) / 100);
+ bitrate.layer_id = i;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id, &bitrate);
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
+ rc = msm_vidc_check_scaling_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+ return -EINVAL;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to get Buffer Requirements : %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_set_persist_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
+ goto fail_start;
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto fail_start;
+ }
+ msm_dcvs_init_load(inst);
+ mutex_lock(&inst->pendingq.lock);
+ list_for_each_safe(ptr, next, &inst->pendingq.list) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ mutex_unlock(&inst->pendingq.lock);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static void msm_venc_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ return /*-EINVAL*/;
+ }
+ inst = q->drv_priv;
+ dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ break;
+ default:
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ /*return rc;*/
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+static int msm_venc_buf_init(struct vb2_buffer *vb)
+{
+ int rc = 0, i = 0;
+ struct vb2_queue *q = vb->vb2_queue;
+ struct msm_vidc_inst *inst = q->drv_priv;
+ struct buffer_info* binfo = NULL;
+ struct vidc_buffer_addr_info buffer_info;
+ enum hal_buffer buffer_type = HAL_BUFFER_INPUT;
+ struct dma_buf* dbuf;
+ struct hfi_device *hdev;
+
+ dprintk(VIDC_DBG, "msm_venc_buf_init \n");
+ if (q->memory == V4L2_MEMORY_USERPTR ||
+ q->memory == V4L2_MEMORY_DMABUF) {
+ dprintk(VIDC_DBG,
+ "Ignore buf init for userptr & DMABUF modes");
+ return rc;
+ }
+ if (!inst) {
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ buffer_type = HAL_BUFFER_INPUT;
+ else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ buffer_type = HAL_BUFFER_OUTPUT;
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ if (vb->vb2_queue->mem_ops->get_dmabuf != NULL) {
+ dbuf = vb->vb2_queue->mem_ops->get_dmabuf(
+ vb->planes[i].mem_priv, 0);
+ }
+ else {
+ dprintk(VIDC_ERR, "get_dmabuf is not supported \n");
+ rc = -EINVAL;
+ goto free_binfo;
+ }
+ binfo->handle[i] = msm_smem_map_dma_buf(
+ inst->mem_client, dbuf, buffer_type);
+ binfo->mapped[i] = true;
+ binfo->device_addr[i] = binfo->handle[i]->device_addr;
+ binfo->size[i] = vb->v4l2_planes[i].length;
+ dprintk(VIDC_DBG, "%s: device_addr 0x %pa, index %d, plane %d, size %d",
+ __func__, &binfo->device_addr[i], vb->v4l2_buf.index, i, binfo->size[i]);
+ }
+ binfo->num_planes = vb->num_planes;
+ binfo->memory = q->memory;
+ binfo->v4l2_index = vb->v4l2_buf.index;
+ binfo->type = q->type;
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_add_tail(&binfo->list, &inst->registeredbufs.list);
+ mutex_unlock(&inst->registeredbufs.lock);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ //set buffer to FW, TODO move to dymaic buf mode
+ buffer_info.buffer_size = vb->v4l2_planes[0].length;
+ buffer_info.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = binfo->device_addr[0];
+ buffer_info.extradata_addr = 0;
+ buffer_info.extradata_size = 0;
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
+ }
+
+ return rc;
+free_binfo:
+ kfree(binfo);
+ return rc;
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+ .queue_setup = msm_venc_queue_setup,
+ .buf_init = msm_venc_buf_init,
+ .start_streaming = msm_venc_start_streaming,
+ .buf_queue = msm_venc_buf_queue,
+ .stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+ return &msm_venc_vb2q_ops;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+ struct v4l2_ctrl **cluster, int ncontrols)
+{
+ int c;
+
+ for (c = 0; c < ncontrols; ++c)
+ if (cluster[c]->id == id)
+ return cluster[c];
+ return NULL;
+}
+
+/* Helper function to translate V4L2_* to HAL_* */
+static inline int venc_v4l2_to_hal(int id, int value)
+{
+ switch (id) {
+ /* MPEG4 */
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+ return HAL_MPEG4_LEVEL_0;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+ return HAL_MPEG4_LEVEL_0b;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+ return HAL_MPEG4_LEVEL_1;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+ return HAL_MPEG4_LEVEL_2;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+ return HAL_MPEG4_LEVEL_3;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+ return HAL_MPEG4_LEVEL_4;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+ return HAL_MPEG4_LEVEL_5;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ return HAL_MPEG4_PROFILE_SIMPLE;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+ default:
+ goto unknown_value;
+ }
+ /* H264 */
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ return HAL_H264_PROFILE_BASELINE;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ return HAL_H264_PROFILE_CONSTRAINED_BASE;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ return HAL_H264_PROFILE_MAIN;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ return HAL_H264_PROFILE_EXTENDED;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ return HAL_H264_PROFILE_HIGH;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+ return HAL_H264_PROFILE_HIGH10;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+ return HAL_H264_PROFILE_HIGH422;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+ return HAL_H264_PROFILE_HIGH444;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+ return HAL_H264_PROFILE_CONSTRAINED_HIGH;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return HAL_H264_LEVEL_1;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return HAL_H264_LEVEL_1b;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return HAL_H264_LEVEL_11;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return HAL_H264_LEVEL_12;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return HAL_H264_LEVEL_13;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return HAL_H264_LEVEL_2;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return HAL_H264_LEVEL_21;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return HAL_H264_LEVEL_22;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return HAL_H264_LEVEL_3;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return HAL_H264_LEVEL_31;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return HAL_H264_LEVEL_32;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return HAL_H264_LEVEL_4;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return HAL_H264_LEVEL_41;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return HAL_H264_LEVEL_42;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return HAL_H264_LEVEL_5;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ return HAL_H264_LEVEL_51;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+ return HAL_H264_LEVEL_52;
+ default:
+ goto unknown_value;
+ }
+ /* H263 */
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+ return HAL_H263_PROFILE_BASELINE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+ return HAL_H263_PROFILE_H320CODING;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+ return HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+ return HAL_H263_PROFILE_ISWV2;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+ return HAL_H263_PROFILE_ISWV3;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+ return HAL_H263_PROFILE_HIGHCOMPRESSION;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+ return HAL_H263_PROFILE_INTERNET;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+ return HAL_H263_PROFILE_INTERLACE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+ return HAL_H263_PROFILE_HIGHLATENCY;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
+ return HAL_H264_ENTROPY_CAVLC;
+ case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
+ return HAL_H264_ENTROPY_CABAC;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+ switch (value) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0:
+ return HAL_H264_CABAC_MODEL_0;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1:
+ return HAL_H264_CABAC_MODEL_1;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2:
+ return HAL_H264_CABAC_MODEL_2;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+ return HAL_H263_LEVEL_10;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+ return HAL_H263_LEVEL_20;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+ return HAL_H263_LEVEL_30;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+ return HAL_H263_LEVEL_40;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+ return HAL_H263_LEVEL_45;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+ return HAL_H263_LEVEL_50;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+ return HAL_H263_LEVEL_60;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+ return HAL_H263_LEVEL_70;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+ return HAL_VPX_PROFILE_VERSION_0;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+ return HAL_VPX_PROFILE_VERSION_1;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+ return HAL_VPX_PROFILE_VERSION_2;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+ return HAL_VPX_PROFILE_VERSION_3;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+ return HAL_VPX_PROFILE_UNUSED;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN:
+ return HAL_HEVC_PROFILE_MAIN;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10:
+ return HAL_HEVC_PROFILE_MAIN10;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC:
+ return HAL_HEVC_PROFILE_MAIN_STILL_PIC;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2:
+ return HAL_HEVC_MAIN_TIER_LEVEL_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_2_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3:
+ return HAL_HEVC_MAIN_TIER_LEVEL_3;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_3_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4:
+ return HAL_HEVC_MAIN_TIER_LEVEL_4;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_4_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5:
+ return HAL_HEVC_MAIN_TIER_LEVEL_5;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_5_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2:
+ return HAL_HEVC_MAIN_TIER_LEVEL_5_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6:
+ return HAL_HEVC_MAIN_TIER_LEVEL_6;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1:
+ return HAL_HEVC_MAIN_TIER_LEVEL_6_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2:
+ return HAL_HEVC_MAIN_TIER_LEVEL_6_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2:
+ return HAL_HEVC_HIGH_TIER_LEVEL_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_2_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3:
+ return HAL_HEVC_HIGH_TIER_LEVEL_3;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_3_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4:
+ return HAL_HEVC_HIGH_TIER_LEVEL_4;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_4_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5:
+ return HAL_HEVC_HIGH_TIER_LEVEL_5;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_5_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2:
+ return HAL_HEVC_HIGH_TIER_LEVEL_5_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6:
+ return HAL_HEVC_HIGH_TIER_LEVEL_6;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
+ return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+ switch (value) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
+ return HAL_ROTATE_NONE;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90:
+ return HAL_ROTATE_90;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180:
+ return HAL_ROTATE_180;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270:
+ return HAL_ROTATE_270;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+ return HAL_H264_DB_MODE_DISABLE;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+ return HAL_H264_DB_MODE_ALL_BOUNDARY;
+ case L_MODE:
+ return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+ default:
+ goto unknown_value;
+ }
+ }
+
+unknown_value:
+ dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+ return -EINVAL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ struct hal_request_iframe request_iframe;
+ struct hal_bitrate bitrate;
+ struct hal_profile_level profile_level;
+ struct hal_h264_entropy_control h264_entropy_control;
+ struct hal_quantization quantization;
+ struct hal_intra_period intra_period;
+ struct hal_idr_period idr_period;
+ struct hal_operations operations;
+ struct hal_intra_refresh intra_refresh;
+ struct hal_multi_slice_control multi_slice_control;
+ struct hal_h264_db_control h264_db_control;
+ struct hal_enable enable;
+ struct hal_h264_vui_timing_info vui_timing_info;
+ struct hal_quantization_range qp_range;
+ struct hal_h264_vui_bitstream_restrc vui_bitstream_restrict;
+ struct hal_preserve_text_quality preserve_text_quality;
+ u32 property_id = 0, property_val = 0;
+ void *pdata = NULL;
+ struct v4l2_ctrl *temp_ctrl = NULL;
+ struct hfi_device *hdev;
+ struct hal_extradata_enable extra;
+ struct hal_mpeg4_time_resolution time_res;
+ struct hal_ltr_use use_ltr;
+ struct hal_ltr_mark mark_ltr;
+ struct hal_hybrid_hierp hyb_hierp;
+ u32 hier_p_layers = 0, hier_b_layers = 0;
+ struct hal_venc_perf_mode venc_mode;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ /* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+ struct v4l2_ctrl *__temp; \
+ __temp = get_ctrl_from_cluster( \
+ __ctrl_id, \
+ ctrl->cluster, ctrl->ncontrols); \
+ if (!__temp) { \
+ dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+ #__ctrl_id, __ctrl_id); \
+ /* Clusters are hardcoded, if we can't find */ \
+ /* something then things are massively screwed up */ \
+ BUG_ON(1); \
+ } \
+ __temp; \
+ })
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
+ if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
+ inst->fmts[CAPTURE_PORT]->fourcc !=
+ V4L2_PIX_FMT_H264_NO_SC) {
+ dprintk(VIDC_ERR, "Control %#x only valid for H264\n",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ property_id =
+ HAL_CONFIG_VENC_IDR_PERIOD;
+ idr_period.idr_period = ctrl->val;
+ pdata = &idr_period;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+ case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+ {
+ int num_p, num_b;
+
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+ num_b = temp_ctrl->val;
+
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
+ num_p = temp_ctrl->val;
+
+ if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES)
+ num_p = ctrl->val;
+ else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES)
+ num_b = ctrl->val;
+
+ if (num_b) {
+ u32 max_num_b_frames = MAX_NUM_B_FRAMES;
+ property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
+ pdata = &max_num_b_frames;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id, pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed : Setprop MAX_NUM_B_FRAMES %d\n",
+ rc);
+ break;
+ }
+ }
+
+ property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+ intra_period.pframes = num_p;
+ intra_period.bframes = num_b;
+ pdata = &intra_period;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
+ property_id =
+ HAL_CONFIG_VENC_REQUEST_IFRAME;
+ request_iframe.enable = true;
+ pdata = &request_iframe;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ {
+ int final_mode = 0;
+ struct v4l2_ctrl update_ctrl = {.id = 0};
+
+ /* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL
+ * manipulate the same thing. If one control's state
+ * changes, try to mirror the state in the other control's
+ * value */
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) {
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+ final_mode = HAL_RATE_CONTROL_VBR_CFR;
+ update_ctrl.val =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
+ } else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */
+ final_mode = HAL_RATE_CONTROL_CBR_CFR;
+ update_ctrl.val =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+ }
+
+ update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
+
+ } else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) {
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+ update_ctrl.val =
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+ update_ctrl.val =
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
+
+ final_mode = ctrl->val;
+ update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
+ }
+
+ if (update_ctrl.id) {
+ temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
+ temp_ctrl->val = update_ctrl.val;
+ }
+
+ property_id = HAL_PARAM_VENC_RATE_CONTROL;
+ property_val = final_mode;
+ pdata = &property_val;
+
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ {
+ struct v4l2_ctrl *hier_p = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS);
+
+ bitrate.layer_id = 0;
+ if (hier_p->val &&
+ inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264) {
+ rc = set_bitrate_for_each_layer(inst,
+ hier_p->val, ctrl->val);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "failed to set bitrate for multiple layers\n");
+ rc = -EINVAL;
+ }
+ } else {
+ property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+ bitrate.bit_rate = ctrl->val;
+ bitrate.layer_id = 0;
+ pdata = &bitrate;
+ }
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ {
+ struct v4l2_ctrl *avg_bitrate = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_BITRATE);
+
+ if (ctrl->val < avg_bitrate->val) {
+ dprintk(VIDC_ERR,
+ "Peak bitrate (%d) is lower than average bitrate (%d)\n",
+ ctrl->val, avg_bitrate->val);
+ rc = -EINVAL;
+ break;
+ } else if (ctrl->val < avg_bitrate->val * 2) {
+ dprintk(VIDC_WARN,
+ "Peak bitrate (%d) ideally should be twice the average bitrate (%d)\n",
+ ctrl->val, avg_bitrate->val);
+ }
+
+ property_id = HAL_CONFIG_VENC_MAX_BITRATE;
+ bitrate.bit_rate = ctrl->val;
+ bitrate.layer_id = 0;
+ pdata = &bitrate;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ temp_ctrl = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL);
+
+ property_id =
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+ h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+ h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+ temp_ctrl->val);
+ pdata = &h264_entropy_control;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE);
+
+ property_id =
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+ h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+ h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+ temp_ctrl->val);
+ pdata = &h264_entropy_control;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ dprintk(VIDC_DBG, "\nprofile: %d\n",
+ profile_level.profile);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ dprintk(VIDC_DBG, "\nLevel: %d\n",
+ profile_level.level);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE);
+
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ ctrl->val);
+ profile_level.level = HAL_VPX_PROFILE_UNUSED;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+ temp_ctrl =
+ TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE);
+
+ property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ temp_ctrl->val);
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+ {
+ struct v4l2_ctrl *deinterlace = NULL;
+ if (!(inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
+ dprintk(VIDC_ERR, "Rotation not supported: %#x\n",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ deinterlace =
+ TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE);
+ if (ctrl->val && deinterlace && deinterlace->val !=
+ V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED) {
+ dprintk(VIDC_ERR,
+ "Rotation not supported with deinterlacing\n");
+ rc = -EINVAL;
+ break;
+ }
+ property_id =
+ HAL_CONFIG_VPE_OPERATIONS;
+ operations.rotate = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+ ctrl->val);
+ operations.flip = HAL_FLIP_NONE;
+ pdata = &operations;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
+ struct v4l2_ctrl *qpp, *qpb;
+
+ qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+ qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpi = ctrl->val;
+ quantization.qpp = qpp->val;
+ quantization.qpb = qpb->val;
+ quantization.layer_id = 0;
+
+ pdata = &quantization;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: {
+ struct v4l2_ctrl *qpi, *qpb;
+
+ qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+ qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpp = ctrl->val;
+ quantization.qpi = qpi->val;
+ quantization.qpb = qpb->val;
+ quantization.layer_id = 0;
+
+ pdata = &quantization;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: {
+ struct v4l2_ctrl *qpi, *qpp;
+
+ qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+ qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpb = ctrl->val;
+ quantization.qpi = qpi->val;
+ quantization.qpp = qpp->val;
+ quantization.layer_id = 0;
+
+ pdata = &quantization;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: {
+ struct v4l2_ctrl *qp_max;
+
+ qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+ if (ctrl->val >= qp_max->val) {
+ dprintk(VIDC_ERR,
+ "Bad range: Min QP (%d) > Max QP(%d)\n",
+ ctrl->val, qp_max->val);
+ rc = -ERANGE;
+ break;
+ }
+
+ property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+ qp_range.layer_id = 0;
+ qp_range.max_qp = qp_max->val;
+ qp_range.min_qp = ctrl->val;
+
+ pdata = &qp_range;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: {
+ struct v4l2_ctrl *qp_min;
+
+ qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+ if (ctrl->val <= qp_min->val) {
+ dprintk(VIDC_ERR,
+ "Bad range: Max QP (%d) < Min QP(%d)\n",
+ ctrl->val, qp_min->val);
+ rc = -ERANGE;
+ break;
+ }
+
+ property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+ qp_range.layer_id = 0;
+ qp_range.max_qp = ctrl->val;
+ qp_range.min_qp = qp_min->val;
+
+ pdata = &qp_range;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: {
+ struct v4l2_ctrl *qp_max;
+ qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP);
+ property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+ qp_range.layer_id = 0;
+ qp_range.max_qp = qp_max->val;
+ qp_range.min_qp = ctrl->val;
+ pdata = &qp_range;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: {
+ struct v4l2_ctrl *qp_min;
+ qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP);
+ property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+ qp_range.layer_id = 0;
+ qp_range.max_qp = ctrl->val;
+ qp_range.min_qp = qp_min->val;
+ pdata = &qp_range;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
+ int temp = 0;
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ default:
+ temp = 0;
+ break;
+ }
+
+ if (temp)
+ temp_ctrl = TRY_GET_CTRL(temp);
+
+ property_id =
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+ multi_slice_control.multi_slice = ctrl->val;
+ multi_slice_control.slice_size = temp ? temp_ctrl->val : 0;
+
+ pdata = &multi_slice_control;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+
+ property_id =
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+ multi_slice_control.multi_slice = temp_ctrl->val;
+ multi_slice_control.slice_size = ctrl->val;
+ pdata = &multi_slice_control;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
+ bool codec_avc =
+ inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264 ||
+ inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264_NO_SC;
+
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+ if (codec_avc && temp_ctrl->val ==
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
+ enable.enable = true;
+ } else {
+ dprintk(VIDC_WARN,
+ "Failed : slice delivery mode is valid "\
+ "only for H264 encoder and MB based slicing\n");
+ enable.enable = false;
+ }
+ pdata = &enable;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
+ struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+ property_id =
+ HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.mode = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
+ pdata = &intra_refresh;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: {
+ struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs;
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.air_mbs = ctrl->val;
+ intra_refresh.mode = ir_mode->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
+ pdata = &intra_refresh;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: {
+ struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs;
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.air_ref = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.mode = ir_mode->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
+ pdata = &intra_refresh;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: {
+ struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref;
+
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.cir_mbs = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.mode = ir_mode->val;
+
+ pdata = &intra_refresh;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+ struct v4l2_ctrl *air_mbs, *air_ref;
+
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.cir_mbs = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+ pdata = &intra_refresh;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ {
+ struct v4l2_ctrl *alpha, *beta;
+
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ ctrl->val);
+ pdata = &h264_db_control;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ {
+ struct v4l2_ctrl *mode, *beta;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = ctrl->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
+ pdata = &h264_db_control;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ {
+ struct v4l2_ctrl *mode, *alpha;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
+ h264_db_control.slice_beta_offset = ctrl->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
+ pdata = &h264_db_control;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ property_id =
+ HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+ enable.enable = 0;
+ break;
+ case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+ enable.enable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+ default:
+ rc = -ENOTSUPP;
+ break;
+ }
+ pdata = &enable;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+ inst->flags |= VIDC_SECURE;
+ dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
+ !!(inst->flags & VIDC_SECURE));
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ property_id = HAL_PARAM_INDEX_EXTRADATA;
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+ extra.enable = 1;
+ pdata = &extra;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ {
+ struct v4l2_ctrl *rc_mode;
+ bool cfr = false;
+
+ property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
+ rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+
+ switch (rc_mode->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+ cfr = true;
+ break;
+ default:
+ cfr = false;
+ break;
+ }
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED:
+ vui_timing_info.enable = 0;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
+ vui_timing_info.enable = 1;
+ vui_timing_info.fixed_frame_rate = cfr;
+ vui_timing_info.time_scale = NSEC_PER_SEC;
+ }
+
+ pdata = &vui_timing_info;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+ property_id = HAL_PARAM_VENC_H264_GENERATE_AUDNAL;
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED:
+ enable.enable = 0;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED:
+ enable.enable = 1;
+ break;
+ default:
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ pdata = &enable;
+ break;
+ case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+ inst->flags |= VIDC_NOMINAL;
+ break;
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+ inst->flags |= VIDC_TURBO;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT:
+ property_id = HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC;
+ vui_bitstream_restrict.enable = ctrl->val;
+ pdata = &vui_bitstream_restrict;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY:
+ property_id = HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY;
+ preserve_text_quality.enable = ctrl->val;
+ pdata = &preserve_text_quality;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION:
+ property_id = HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+ time_res.time_increment_resolution = ctrl->val;
+ pdata = &time_res;
+ break;
+
+ case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+ {
+ struct v4l2_ctrl *rotation = NULL;
+ if (!(inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY)) {
+ dprintk(VIDC_ERR, "Deinterlace not supported: %#x\n",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ rotation = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+ if (ctrl->val && rotation && rotation->val !=
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) {
+ dprintk(VIDC_ERR,
+ "Deinterlacing not supported with rotation");
+ rc = -EINVAL;
+ break;
+ }
+ property_id = HAL_CONFIG_VPE_DEINTERLACE;
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED:
+ enable.enable = 1;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED:
+ default:
+ enable.enable = 0;
+ break;
+ }
+ pdata = &enable;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER:
+ atomic_inc(&inst->seq_hdr_reqs);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
+ property_id = HAL_CONFIG_VENC_USELTRFRAME;
+ use_ltr.ref_ltr = (1 << ctrl->val);
+ use_ltr.use_constraint = false;
+ use_ltr.frames = 0;
+ pdata = &use_ltr;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME:
+ property_id = HAL_CONFIG_VENC_MARKLTRFRAME;
+ mark_ltr.mark_frame = ctrl->val;
+ pdata = &mark_ltr;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
+ property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
+ hier_p_layers = ctrl->val;
+ rc = msm_venc_toggle_hier_p(inst, ctrl->val);
+ if (rc)
+ break;
+ if (hier_p_layers > inst->capability.hier_p.max) {
+ dprintk(VIDC_ERR,
+ "Error setting hier p num layers = %d max supported by f/w = %d\n",
+ hier_p_layers,
+ inst->capability.hier_p.max);
+ rc = -ENOTSUPP;
+ break;
+ }
+ pdata = &hier_p_layers;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE:
+ property_id = HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP;
+ enable.enable = (ctrl->val ==
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE);
+ pdata = &enable;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE:
+ property_id = HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE;
+ enable.enable = ctrl->val;
+ pdata = &enable;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC:
+ property_id = HAL_PARAM_VENC_H264_NAL_SVC_EXT;
+ enable.enable = ctrl->val;
+ pdata = &enable;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE:
+ property_id = HAL_CONFIG_VENC_PERF_MODE;
+ venc_mode.mode = ctrl->val;
+ pdata = &venc_mode;
+ msm_dcvs_enc_set_power_save_mode(inst,
+ venc_mode.mode ==
+ V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
+ if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_HEVC) {
+ dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+ property_id = HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS;
+ hier_b_layers = ctrl->val;
+ pdata = &hier_b_layers;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE:
+ property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE;
+ hyb_hierp.layers = ctrl->val;
+ pdata = &hyb_hierp;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+#undef TRY_GET_CTRL
+
+ if (!rc && property_id) {
+ dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
+ property_id,
+ ctrl->val);
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id, pdata);
+ }
+
+ return rc;
+}
+
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+ struct v4l2_ext_controls *ctrl)
+{
+ int rc = 0, i;
+ struct v4l2_ext_control *control;
+ struct hfi_device *hdev;
+ struct hal_ltr_mode ltr_mode;
+ struct hal_vc1e_perf_cfg_type search_range = { {0} };
+ u32 property_id = 0;
+ void *pdata = NULL;
+ struct msm_vidc_core_capability *cap = NULL;
+ struct hal_initial_quantization quant;
+
+ if (!inst || !inst->core || !inst->core->device || !ctrl) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ cap = &inst->capability;
+
+ control = ctrl->controls;
+ for (i = 0; i < ctrl->count; i++) {
+ switch (control[i].id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
+ if (control[i].value !=
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE) {
+ rc = msm_venc_toggle_hier_p(inst, false);
+ if (rc)
+ break;
+ }
+ ltr_mode.mode = control[i].value;
+ ltr_mode.trust_mode = 1;
+ property_id = HAL_PARAM_VENC_LTRMODE;
+ pdata = &ltr_mode;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
+ ltr_mode.count = control[i].value;
+ if (ltr_mode.count > cap->ltr_count.max) {
+ dprintk(VIDC_ERR,
+ "Invalid LTR count %d. Supported max: %d\n",
+ ltr_mode.count,
+ cap->ltr_count.max);
+ /*
+ * FIXME: Return an error (-EINVALID)
+ * here once VP8 supports LTR count
+ * capability
+ */
+ ltr_mode.count = 1;
+ }
+ ltr_mode.trust_mode = 1;
+ property_id = HAL_PARAM_VENC_LTRMODE;
+ pdata = &ltr_mode;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP:
+ property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+ quant.init_qp_enable = control[i].value;
+ pdata = &quant;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
+ quant.qpi = control[i].value;
+ property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+ pdata = &quant;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
+ quant.qpp = control[i].value;
+ property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+ pdata = &quant;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
+ quant.qpb = control[i].value;
+ property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+ pdata = &quant;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE:
+ search_range.i_frame.x_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE:
+ search_range.i_frame.y_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE:
+ search_range.p_frame.x_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE:
+ search_range.p_frame.y_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE:
+ search_range.b_frame.x_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE:
+ search_range.b_frame.y_subsampled = control[i].value;
+ property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+ pdata = &search_range;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid id set: %d\n",
+ control[i].id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ if (rc)
+ break;
+ }
+
+ if (!rc && property_id) {
+ dprintk(VIDC_DBG, "Control: HAL property=%x\n", property_id);
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id, pdata);
+ }
+ return rc;
+}
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+ int rc = 0, c = 0;
+
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto failed_open_done;
+ }
+
+ for (c = 0; c < ctrl->ncontrols; ++c) {
+ if (ctrl->cluster[c]->is_new) {
+ struct v4l2_ctrl *temp = ctrl->cluster[c];
+
+ rc = try_set_ctrl(inst, temp);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed setting %s (%x)\n",
+ v4l2_ctrl_get_name(temp->id),
+ temp->id);
+ break;
+ }
+ }
+ }
+failed_open_done:
+ if (rc)
+ dprintk(VIDC_ERR, "Failed setting control: %x (%s)",
+ ctrl->id, v4l2_ctrl_get_name(ctrl->id));
+ return rc;
+}
+
+static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_venc_ctrl_ops = {
+
+ .s_ctrl = msm_venc_op_s_ctrl,
+ .g_volatile_ctrl = msm_venc_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_venc_get_ctrl_ops(void)
+{
+ return &msm_venc_ctrl_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[CAPTURE_PORT] = &venc_formats[2];
+ inst->fmts[OUTPUT_PORT] = &venc_formats[0];
+ inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+ inst->prop.fps = 15;
+ inst->capability.pixelprocess_capabilities = 0;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+ return rc;
+}
+
+int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl);
+}
+int msm_venc_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+
+int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst,
+ struct v4l2_ext_controls *ctrl)
+{
+ int rc = 0;
+ if (ctrl->ctrl_class != V4L2_CTRL_CLASS_MPEG) {
+ dprintk(VIDC_ERR, "Invalid Class set for extended control\n");
+ return -EINVAL;
+ }
+ rc = try_set_ext_ctrl(inst, ctrl);
+ if (rc) {
+ dprintk(VIDC_ERR, "Error setting extended control\n");
+ return rc;
+ }
+ return rc;
+}
+
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+ core = inst->core;
+ switch (enc->cmd) {
+ case V4L2_ENC_QCOM_CMD_FLUSH:
+ rc = msm_comm_flush(inst, enc->flags);
+ break;
+ case V4L2_ENC_CMD_STOP:
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
+ return rc;
+ }
+ rc = msm_comm_release_scratch_buffers(inst, false);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release scratch buf:%d\n",
+ rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release persist buf:%d\n",
+ rc);
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ /* Clients rely on this event for joining poll thread.
+ * This event should be returned even if firmware has
+ * failed to respond */
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
+ break;
+ }
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Command: %d failed with rc = %d\n", enc->cmd, rc);
+ return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
+ cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ dprintk(VIDC_DBG, "No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u32 property_id = 0;
+ u64 us_per_frame = 0;
+ void *pdata;
+ int rc = 0, fps = 0;
+ struct hal_frame_rate frame_rate;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ property_id = HAL_CONFIG_FRAME_RATE;
+
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator *
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
+ break;
+ }
+ }
+
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ fps = USEC_PER_SEC;
+ do_div(fps, us_per_frame);
+
+ if (fps % 15 == 14 || fps % 24 == 23)
+ fps = fps + 1;
+ else if (fps % 24 == 1 || fps % 15 == 1)
+ fps = fps - 1;
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
+ frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
+ frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &frame_rate;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id, pdata);
+
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to set frame rate %d\n", rc);
+ }
+
+ msm_comm_scale_clocks_and_bus(inst);
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_set_csc(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int count = 0;
+ struct hal_vpe_color_space_conversion vpe_csc;
+
+ while (count < HAL_MAX_MATRIX_COEFFS) {
+ if (count < HAL_MAX_BIAS_COEFFS)
+ vpe_csc.csc_bias[count] =
+ vpe_csc_601_to_709_bias_coeff[count];
+ if (count < HAL_MAX_LIMIT_COEFFS)
+ vpe_csc.csc_limit[count] =
+ vpe_csc_601_to_709_limit_coeff[count];
+ vpe_csc.csc_matrix[count] =
+ vpe_csc_601_to_709_matrix_coeff[count];
+ count = count + 1;
+ }
+ rc = msm_comm_try_set_prop(inst,
+ HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
+ if (rc)
+ dprintk(VIDC_ERR, "Setting VPE coefficients failed\n");
+
+ return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ struct hfi_device *hdev;
+ if (!inst || !f) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+
+ if (!inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ if (msm_vidc_vpe_csc_601_to_709) {
+ msm_venc_set_csc(inst);
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (!fmt || fmt->type != CAPTURE_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct hal_frame_size frame_sz;
+
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
+
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->prop.width[OUTPUT_PORT];
+ frame_sz.height = inst->prop.height[OUTPUT_PORT];
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set framesize for Output port\n");
+ goto exit;
+ }
+
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set hal property for framesize\n");
+ goto exit;
+ }
+
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (!fmt || fmt->type != OUTPUT_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc);
+ } else {
+ dprintk(VIDC_ERR, "%s - Unsupported buf type: %d\n",
+ __func__, f->type);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ inst->fmts[fmt->type] = fmt;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->get_frame_size(i,
+ f->fmt.pix_mp.height, f->fmt.pix_mp.width);
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct hal_frame_size frame_sz = {0};
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ goto exit;
+ }
+
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_FRAME_SIZE,
+ &frame_sz);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set OUTPUT framesize\n");
+ goto exit;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct hal_buffer_requirements *bufreq = NULL;
+ int extra_idx = 0;
+
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_INPUT);
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ bufreq ? bufreq->buffer_size : 0;
+ }
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ u32 height, width;
+ unsigned int extra_idx = 0;
+ struct hal_buffer_requirements *bufreq = NULL;
+
+ if (!inst || !f) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_WARN, "Getting buffer requirements failed: %d\n",
+ rc);
+ return rc;
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = inst->fmts[CAPTURE_PORT];
+ height = inst->prop.height[CAPTURE_PORT];
+ width = inst->prop.width[CAPTURE_PORT];
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = inst->fmts[OUTPUT_PORT];
+ height = inst->prop.height[OUTPUT_PORT];
+ width = inst->prop.width[OUTPUT_PORT];
+ } else {
+ dprintk(VIDC_ERR, "Invalid type: %x\n", f->type);
+ return -ENOTSUPP;
+ }
+
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = height;
+ f->fmt.pix_mp.width = width;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, height, width);
+ }
+
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_INPUT);
+
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ bufreq ? bufreq->buffer_size : 0;
+ }
+
+ for (i = 0; i < fmt->num_planes; ++i) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+ }
+
+ return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ mutex_lock(&q->lock);
+ rc = vb2_reqbufs(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info = {0};
+ struct hfi_device *hdev;
+ int extra_idx = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core %p in bad state, ignoring prepare buf\n",
+ inst->core);
+ goto exit;
+ }
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+
+ for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); i++) {
+ dprintk(VIDC_DBG, "device_addr = %#lx, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG, "extradata: %#lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
+ }
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_release_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int i, rc = 0, extra_idx = 0;
+ struct vidc_buffer_addr_info buffer_info = {0};
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to release res done state\n",
+ inst);
+ goto exit;
+ }
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; i < b->length; i++) {
+ dprintk(VIDC_DBG,
+ "Release device_addr = %#lx, size = %d, %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length, inst->state);
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_release_buffers failed\n");
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ mutex_lock(&q->lock);
+ rc = vb2_qbuf(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buf_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ mutex_lock(&q->lock);
+ rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct buf_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "Calling streamon\n");
+ mutex_lock(&q->lock);
+ rc = vb2_streamon(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct buf_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
+ mutex_lock(&q->lock);
+ rc = vb2_streamoff(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
+ if (rc)
+ dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+ int *size)
+{
+ int c = 0, sz = 0;
+ struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+ NUM_CTRLS, GFP_KERNEL);
+
+ if (!size || !cluster || !inst)
+ return NULL;
+
+ for (c = 0; c < NUM_CTRLS; c++)
+ cluster[sz++] = inst->ctrls[c];
+
+ *size = sz;
+ return cluster;
+}
+
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
+{
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
+ int ret_val = 0;
+ int cluster_size = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS,
+ GFP_KERNEL);
+ if (!inst->ctrls) {
+ dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+ if (ret_val) {
+ dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ struct v4l2_ctrl *ctrl = NULL;
+ if (IS_PRIV_CTRL(msm_venc_ctrls[idx].id)) {
+ ctrl_cfg.def = msm_venc_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_venc_ctrls[idx].id;
+ ctrl_cfg.max = msm_venc_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_venc_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_venc_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_venc_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_venc_ctrl_ops;
+ ctrl_cfg.step = msm_venc_ctrls[idx].step;
+ ctrl_cfg.type = msm_venc_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_venc_ctrls[idx].qmenu;
+ ctrl = v4l2_ctrl_new_custom(
+ &inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_venc_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ ctrl = v4l2_ctrl_new_std_menu(
+ &inst->ctrl_handler,
+ &msm_venc_ctrl_ops,
+ msm_venc_ctrls[idx].id,
+ msm_venc_ctrls[idx].maximum,
+ msm_venc_ctrls[idx].menu_skip_mask,
+ msm_venc_ctrls[idx].default_value);
+ } else {
+ ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_venc_ctrl_ops,
+ msm_venc_ctrls[idx].id,
+ msm_venc_ctrls[idx].minimum,
+ msm_venc_ctrls[idx].maximum,
+ msm_venc_ctrls[idx].step,
+ msm_venc_ctrls[idx].default_value);
+ }
+ }
+
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val) {
+ dprintk(VIDC_ERR,
+ "Error adding ctrl (%s) to ctrl handle, %d\n",
+ msm_venc_ctrls[idx].name,
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ inst->ctrls[idx] = ctrl;
+ }
+
+ /* Construct a super cluster of all controls */
+ inst->cluster = get_super_cluster(inst, &cluster_size);
+ if (!inst->cluster || !cluster_size) {
+ dprintk(VIDC_WARN,
+ "Failed to setup super cluster\n");
+ return -EINVAL;
+ }
+
+ v4l2_ctrl_cluster(cluster_size, inst->cluster);
+
+ return ret_val;
+}
+
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ kfree(inst->ctrls);
+ kfree(inst->cluster);
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.h b/drivers/media/platform/msm/vidc/msm_venc.h
new file mode 100644
index 000000000000..07afd90cf071
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_venc.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
new file mode 100644
index 000000000000..eb869d8dfdf0
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -0,0 +1,1521 @@
+/* Copyright (c) 2012-2015, 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/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_dcvs.h"
+
+#define MAX_EVENTS 30
+
+/* Offset base for buffers on the destination queue - used to distinguish
+ * between source and destination buffers when mmapping - they receive the same
+ * offsets but for different queues */
+#define DST_QUEUE_OFF_BASE (1 << 30)
+
+static int get_poll_flags(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+ struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+ struct vb2_buffer *out_vb = NULL;
+ struct vb2_buffer *cap_vb = NULL;
+ unsigned long flags;
+ int rc = 0;
+
+ if (v4l2_event_pending(&inst->event_handler))
+ rc |= POLLPRI;
+
+ spin_lock_irqsave(&capq->done_lock, flags);
+ if (!list_empty(&capq->done_list))
+ cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+ done_entry);
+ if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+ || cap_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&capq->done_lock, flags);
+
+ spin_lock_irqsave(&outq->done_lock, flags);
+ if (!list_empty(&outq->done_list))
+ out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+ done_entry);
+ if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+ || out_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&outq->done_lock, flags);
+
+ return rc;
+}
+
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = NULL;
+ struct vb2_queue *capq = NULL;
+
+ if (!inst)
+ return -EINVAL;
+
+ outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+ capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+
+ poll_wait(filp, &inst->event_handler.wait, wait);
+ poll_wait(filp, &capq->done_wq, wait);
+ poll_wait(filp, &outq->done_wq, wait);
+ return get_poll_flags(inst);
+}
+EXPORT_SYMBOL(msm_vidc_poll);
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !cap)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_querycap(instance, cap);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_querycap(instance, cap);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_querycap);
+
+int msm_vidc_s_parm(void *instance,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !a)
+ return -EINVAL;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_parm(instance, a);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_parm(instance, a);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_parm);
+
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !f)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_enum_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_enum_fmt(instance, f);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_enum_fmt);
+
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !f)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_fmt(instance, f);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_fmt(instance, f);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_fmt);
+
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !f)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_fmt(instance, f);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_g_fmt);
+
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !control)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_ctrl(instance, control);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_ctrl(instance, control);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_ctrl);
+
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !control)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_ctrl(instance, control);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_ctrl(instance, control);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_g_ctrl);
+
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (!inst || !control)
+ return -EINVAL;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_ext_ctrl(instance, control);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_ext_ctrl);
+
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_reqbufs(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_reqbufs(instance, b);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_reqbufs);
+
+struct buffer_info *get_registered_mmap_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+
+ if (!inst || !b) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ return NULL;
+ }
+
+ *plane = 0;
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (temp && temp->v4l2_index == b->index
+ && temp->type == b->type) {
+ ret = temp;
+ *plane = 0;
+ //TODO: Add for loop for plane no
+ break;
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+ return ret;
+}
+
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b, int idx, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ int i;
+ int fd = b->m.planes[idx].reserved[0];
+ u32 buff_off = b->m.planes[idx].reserved[1];
+ u32 size = b->m.planes[idx].length;
+ ion_phys_addr_t device_addr = b->m.planes[idx].m.userptr;
+
+ if (fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+
+ *plane = 0;
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+ bool fd_matches = false;
+ bool device_addr_matches = device_addr ==
+ temp->device_addr[i];
+ bool contains_within = CONTAINS(temp->buff_off[i],
+ temp->size[i], buff_off) ||
+ CONTAINS(buff_off, size, temp->buff_off[i]);
+ bool overlaps = OVERLAPS(buff_off, size,
+ temp->buff_off[i], temp->size[i]);
+ if (b->memory == V4L2_MEMORY_DMABUF)
+ fd_matches = fd == temp->fd[i];
+
+ if ((fd_matches || device_addr_matches) &&
+ (contains_within || overlaps)) {
+ dprintk(VIDC_DBG,
+ "This memory region is already mapped\n");
+ dprintk(VIDC_DBG, "**sachins - fd_matches %d, device_addr_matches %d, contains_within %d, overlaps %d\n",
+ fd_matches, device_addr_matches, contains_within, overlaps);
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+err_invalid_input:
+ return ret;
+}
+
+static struct msm_smem *get_same_fd_buffer(struct msm_vidc_list *buf_list,
+ int fd)
+{
+ struct buffer_info *temp;
+ struct msm_smem *same_fd_handle = NULL;
+
+ int i;
+
+ if (!fd)
+ return NULL;
+
+ if (!buf_list || fd < 0) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+
+ mutex_lock(&buf_list->lock);
+ list_for_each_entry(temp, &buf_list->list, list) {
+ for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+ if (temp->fd[i] == fd &&
+ temp->handle[i] && temp->mapped[i]) {
+ temp->same_fd_ref[i]++;
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ same_fd_handle = temp->handle[i];
+ break;
+ }
+ }
+ if (same_fd_handle)
+ break;
+ }
+ mutex_unlock(&buf_list->lock);
+
+err_invalid_input:
+ return same_fd_handle;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+ ion_phys_addr_t device_addr)
+{
+ struct buffer_info *temp = NULL;
+ bool found = false;
+ int i;
+
+ if (!buf_list || !device_addr) {
+ dprintk(VIDC_ERR,
+ "Invalid input- device_addr: %pa buf_list: %p\n",
+ &device_addr, buf_list);
+ goto err_invalid_input;
+ }
+
+ mutex_lock(&buf_list->lock);
+ list_for_each_entry(temp, &buf_list->list, list) {
+ for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+ if (!temp->inactive &&
+ temp->device_addr[i] == device_addr) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+ mutex_unlock(&buf_list->lock);
+
+err_invalid_input:
+ return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+ struct v4l2_buffer *b, u32 i)
+{
+ binfo->type = b->type;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->num_planes = b->length;
+ binfo->memory = b->memory;
+ binfo->v4l2_index = b->index;
+ binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+ binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+ dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+ __func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ b->type = binfo->type;
+ b->length = binfo->num_planes;
+ b->memory = binfo->memory;
+ b->index = binfo->v4l2_index;
+ b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+ b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+ binfo->dequeued = false;
+ for (i = 0; i < binfo->num_planes; ++i) {
+ b->m.planes[i].reserved[0] = binfo->fd[i];
+ b->m.planes[i].reserved[1] = binfo->buff_off[i];
+ b->m.planes[i].length = binfo->size[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "%s %d %d %d %pa\n", __func__, binfo->fd[i],
+ binfo->buff_off[i], binfo->size[i],
+ &binfo->device_addr[i]);
+ }
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+ struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+ struct msm_smem *handle = NULL;
+ handle = msm_comm_smem_user_to_kernel(inst,
+ p->reserved[0],
+ p->reserved[1],
+ buffer_type);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get device buffer address\n", __func__);
+ return NULL;
+ }
+ if (msm_comm_smem_cache_operations(inst, handle,
+ SMEM_CACHE_CLEAN))
+ dprintk(VIDC_WARN,
+ "CACHE Clean failed: %d, %d, %d\n",
+ p->reserved[0],
+ p->reserved[1],
+ p->length);
+ return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+ struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_INPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_OUTPUT;
+ } else {
+ /* FIXME in the future. See comment in msm_comm_get_\
+ * domain_partition. Same problem here. */
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_OUTPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_INPUT;
+ }
+ return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+ struct msm_vidc_inst *inst)
+{
+ return b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC;
+}
+
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ populate_buf_info(binfo, b, i);
+ }
+}
+
+static int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buffer_info *binfo = NULL;
+ struct buffer_info *temp = NULL, *iterator = NULL;
+ int plane = 0;
+ int i = 0, rc = 0;
+ struct msm_smem *same_fd_handle = NULL;
+
+ if (!b || !inst) {
+ dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+ b->length, VIDEO_MAX_PLANES);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (b->memory == V4L2_MEMORY_MMAP) {
+ dprintk(VIDC_DBG, "[MAP] Create binfo = %p mem_offset = %#x type = %d, length = %d\n",
+ binfo, b->m.planes[0].m.mem_offset, b->type, b->length);
+ } else {
+ dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d, length = %d\n",
+ binfo, b->m.planes[0].reserved[0], b->type, b->length);
+ }
+
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ mutex_lock(&inst->sync_lock);
+ temp = get_registered_buf(inst, b, i, &plane);
+ if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
+ dprintk(VIDC_DBG,
+ "This memory region has already been prepared\n");
+ rc = -EINVAL;
+ }
+
+ if (temp && is_dynamic_output_buffer_mode(b, inst) && !i) {
+ /*
+ * Buffer is already present in registered list
+ * increment ref_count, populate new values of v4l2
+ * buffer in existing buffer_info struct.
+ *
+ * We will use the saved buffer info and queue it when
+ * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+ */
+ dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+ temp->inactive = false;
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(iterator,
+ &inst->registeredbufs.list, list) {
+ if (iterator == temp) {
+ rc = buf_ref_get(inst, temp);
+ if (rc > 0) {
+ save_v4l2_buffer(b, temp);
+ rc = -EEXIST;
+ }
+ break;
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+ }
+ mutex_unlock(&inst->sync_lock);
+ if (rc < 0)
+ goto exit;
+
+ same_fd_handle = get_same_fd_buffer(
+ &inst->registeredbufs,
+ b->m.planes[i].reserved[0]);
+
+ populate_buf_info(binfo, b, i);
+ if (same_fd_handle) {
+ binfo->device_addr[i] =
+ same_fd_handle->device_addr + binfo->buff_off[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ binfo->mapped[i] = false;
+ binfo->handle[i] = same_fd_handle;
+ } else {
+ if (inst->map_output_buffer) {
+ binfo->handle[i] =
+ map_buffer(inst, &b->m.planes[i],
+ get_hal_buffer_type(inst, b));
+ if (!binfo->handle[i]) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ binfo->mapped[i] = true;
+ binfo->device_addr[i] =
+ binfo->handle[i]->device_addr +
+ binfo->buff_off[i];
+ b->m.planes[i].m.userptr =
+ binfo->device_addr[i];
+ } else {
+ binfo->device_addr[i] =
+ b->m.planes[i].m.userptr;
+ }
+ }
+ /* We maintain one ref count for all planes*/
+ if (!i && is_dynamic_output_buffer_mode(b, inst)) {
+ rc = buf_ref_get(inst, binfo);
+ if (rc < 0)
+ goto exit;
+ }
+ dprintk(VIDC_DBG,
+ "%s: [MAP] binfo = %p, handle[%d] = %p, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+ __func__, binfo, i, binfo->handle[i],
+ &binfo->device_addr[i], binfo->fd[i],
+ binfo->buff_off[i], binfo->mapped[i]);
+ }
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_add_tail(&binfo->list, &inst->registeredbufs.list);
+ mutex_unlock(&inst->registeredbufs.lock);
+ return 0;
+
+exit:
+ kfree(binfo);
+ return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ struct buffer_info *temp = NULL;
+ bool found = false, keep_node = false;
+
+ if (!inst || !binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p %p\n",
+ __func__, inst, binfo);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst->registeredbufs.lock);
+
+ /*
+ * Make sure the buffer to be unmapped and deleted
+ * from the registered list is present in the list.
+ */
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (temp == binfo) {
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * Free the buffer info only if
+ * - buffer info has not been deleted from registered list
+ * - vidc client has called dqbuf on the buffer
+ * - no references are held on the buffer
+ */
+ if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+ goto exit;
+
+ for (i = 0; i < temp->num_planes; i++) {
+ dprintk(VIDC_DBG,
+ "%s: [UNMAP] binfo = %p, handle[%d] = %p, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+ __func__, temp, i, temp->handle[i],
+ &temp->device_addr[i], temp->fd[i],
+ temp->buff_off[i], temp->mapped[i]);
+ /*
+ * Unmap the handle only if the buffer has been mapped and no
+ * other buffer has a reference to this buffer.
+ * In case of buffers with same fd, we will map the buffer only
+ * once and subsequent buffers will refer to the mapped buffer's
+ * device address.
+ * For buffers which share the same fd, do not unmap and keep
+ * the buffer info in registered list.
+ */
+ if (temp->handle[i] && temp->mapped[i] &&
+ !temp->same_fd_ref[i]) {
+ msm_comm_smem_free(inst,
+ temp->handle[i]);
+ }
+
+ if (temp->same_fd_ref[i])
+ keep_node = true;
+ else {
+ temp->fd[i] = 0;
+ temp->handle[i] = 0;
+ temp->device_addr[i] = 0;
+ temp->uvaddr[i] = 0;
+ }
+ }
+ if (!keep_node) {
+ dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp);
+ list_del(&temp->list);
+ kfree(temp);
+ } else {
+ temp->inactive = true;
+ dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp);
+ }
+exit:
+ mutex_unlock(&inst->registeredbufs.lock);
+ return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ struct v4l2_buffer b = {0};
+ struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+ b.m.planes = plane;
+ repopulate_v4l2_buffer(&b, binfo);
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(inst, &b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(inst, &b);
+
+ return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ int rc = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return -EINVAL;
+ }
+
+ if (!inst->map_output_buffer)
+ return 0;
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n",
+ __func__, inst);
+ return -EINVAL;
+ }
+
+ if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return 0;
+
+
+ for (i = 0; i < binfo->num_planes; i++) {
+ if (binfo->handle[i]) {
+ rc = msm_comm_smem_cache_operations(inst,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to clean caches: %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+ } else
+ dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
+ __func__, i);
+ }
+ return 0;
+}
+
+int msm_vidc_mmap(void* instance, struct vm_area_struct *vma)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst = instance;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (!inst)
+ return -EINVAL;
+
+ if (offset < DST_QUEUE_OFF_BASE) {
+ dprintk(VIDC_DBG, "mmaping output plane\n");
+ rc = vb2_mmap(&inst->bufq[OUTPUT_PORT].vb2_bufq, vma);
+ } else { /* capture */
+ dprintk(VIDC_DBG, "mmaping capture plane\n");
+ vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+ rc = vb2_mmap(&inst->bufq[CAPTURE_PORT].vb2_bufq, vma);
+ }
+
+ return rc;
+}
+
+int msm_vidc_querybuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ int i = 0, rc = 0;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (b->memory != V4L2_MEMORY_MMAP) {
+ dprintk(VIDC_ERR, "Only MMAP bufs can be queried\n");
+ return -EINVAL;
+ }
+
+ dprintk(VIDC_DBG, "Before QueryBuf offset 0x%x for buffer index %d \n",
+ b->m.planes[0].m.mem_offset, b->index);
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ dprintk(VIDC_DBG, "querybuf on output port \n");
+ vb2_querybuf(&inst->bufq[OUTPUT_PORT].vb2_bufq, b);
+ } else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ dprintk(VIDC_DBG, "querybuf on capture port \n");
+ vb2_querybuf(&inst->bufq[CAPTURE_PORT].vb2_bufq, b);
+ for (i = 0; i < b->length; i++) {
+ b->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+ }
+ }
+ return rc;
+}
+
+int msm_vidc_exportbuf(void *instance, struct v4l2_exportbuffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ int rc = 0;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ dprintk(VIDC_DBG, "exportbuf on capture port \n");
+ rc = vb2_expbuf(&inst->bufq[CAPTURE_PORT].vb2_bufq, b);
+ } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ dprintk(VIDC_DBG, "exportbuf on output port \n");
+ rc = vb2_expbuf(&inst->bufq[OUTPUT_PORT].vb2_bufq, b);
+ }
+ return rc;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
+ (b->length > VIDEO_MAX_PLANES)) {
+ dprintk(VIDC_ERR, "%s: wrong input params\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst))
+ return 0;
+
+ /* Map the buffer only for non-kernel clients */
+ /*
+ * TODO: We don't have any kernel clients anymore. Reconsider deleting
+ * the conditional once we confirm that no userspace client sends
+ * reserved[0] == 0
+ */
+ if (b->m.planes[0].reserved[0]) {
+ inst->map_output_buffer = true;
+ if (map_and_register_buf(inst, b))
+ return -EINVAL;
+ }
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_prepare_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_prepare_buf(instance, b);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_prepare_buf);
+
+int msm_vidc_release_buffers(void *instance, int buffer_type)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct buffer_info *bi, *dummy;
+ struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane[VIDEO_MAX_PLANES];
+ int i, rc = 0;
+
+ if (!inst)
+ return -EINVAL;
+
+ if (!inst->in_reconfig) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to release res done\n",
+ inst);
+ }
+ }
+
+ /*
+ * In dynamic buffer mode, driver needs to release resources,
+ * but not call release buffers on firmware, as the buffers
+ * were never registered with firmware.
+ */
+ if (buffer_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ inst->buffer_mode_set[CAPTURE_PORT] ==
+ HAL_BUFFER_MODE_DYNAMIC) {
+ goto free_and_unmap;
+ }
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(bi, &inst->registeredbufs.list, list) {
+ bool release_buf = false;
+
+ if (bi->type == buffer_type) {
+ buffer_info.type = bi->type;
+ for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+ i++) {
+ plane[i].reserved[0] = bi->fd[i];
+ plane[i].reserved[1] = bi->buff_off[i];
+ plane[i].length = bi->size[i];
+ if (bi->memory == V4L2_MEMORY_USERPTR)
+ plane[i].m.userptr = bi->device_addr[i];
+ buffer_info.m.planes = plane;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[i].reserved[0],
+ buffer_info.m.planes[i].reserved[1],
+ buffer_info.m.planes[i].length);
+ }
+ buffer_info.length = bi->num_planes;
+ release_buf = true;
+ }
+
+ if (!release_buf)
+ continue;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ rc = msm_vdec_release_buf(instance,
+ &buffer_info);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ rc = msm_venc_release_buf(instance,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+
+free_and_unmap:
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+ if (bi->type == buffer_type) {
+ list_del(&bi->list);
+ for (i = 0; i < bi->num_planes; i++) {
+ if (bi->handle[i] && bi->mapped[i]) {
+ dprintk(VIDC_DBG,
+ "%s: [UNMAP] binfo = %p, handle[%d] = %p, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+ __func__, bi, i, bi->handle[i],
+ &bi->device_addr[i], bi->fd[i],
+ bi->buff_off[i], bi->mapped[i]);
+ msm_comm_smem_free(inst,
+ bi->handle[i]);
+ }
+ }
+ kfree(bi);
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vidc_release_buffers);
+
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !enc) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_cmd(instance, enc);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_encoder_cmd);
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !dec) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_cmd(instance, dec);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_decoder_cmd);
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct buffer_info *binfo;
+ int plane = 0;
+ int rc = 0;
+ int i;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
+ (b->length > VIDEO_MAX_PLANES)) {
+ dprintk(VIDC_ERR, "%s: wrong input params\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ if (b->m.planes[0].reserved[0])
+ inst->map_output_buffer = true;
+
+ rc = map_and_register_buf(inst, b);
+ if (rc == -EEXIST)
+ return 0;
+ if (rc)
+ return rc;
+ }
+
+ if (b->memory == V4L2_MEMORY_MMAP) {
+ dprintk(VIDC_DBG, "no cache opsi, mmap");
+ goto do_qbuf;
+ }
+
+ for (i = 0; i < b->length; ++i) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ b->m.planes[i].m.userptr = 0;
+ continue;
+ }
+
+ binfo = get_registered_buf(inst, b, i, &plane);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ goto err_invalid_buff;
+ }
+ if (b->memory == V4L2_MEMORY_USERPTR)
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "Queueing device address = %pa\n",
+ &binfo->device_addr[i]);
+
+ if (inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_HEVC_HYBRID && binfo->handle[i] &&
+ b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ rc = msm_comm_smem_cache_operations(inst,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to inv caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_comm_smem_cache_operations(inst,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+ }
+
+do_qbuf:
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_qbuf);
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct buffer_info *buffer_info = NULL;
+ int i = 0, rc = 0;
+
+ if (!inst || !b)
+ return -EINVAL;
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
+ (b->length > VIDEO_MAX_PLANES)) {
+ dprintk(VIDC_ERR, "%s: wrong input params\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ rc = msm_vdec_dqbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ rc = msm_venc_dqbuf(instance, b);
+
+ if (rc)
+ return rc;
+
+ if (b->memory == V4L2_MEMORY_MMAP) {
+ dprintk(VIDC_DBG, "Ignore cache ops for MMAP buffers");
+ return rc;
+ }
+
+ for (i = 0; i < b->length; i++) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].m.userptr) {
+ continue;
+ }
+ buffer_info = device_to_uvaddr(&inst->registeredbufs,
+ b->m.planes[i].m.userptr);
+
+ if (!buffer_info) {
+ dprintk(VIDC_ERR,
+ "%s no buffer info registered for buffer addr: %#lx\n",
+ __func__, b->m.planes[i].m.userptr);
+ return -EINVAL;
+ }
+
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+ if (!b->m.planes[i].m.userptr) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to find user virtual address, %#lx, %d, %d\n",
+ __func__, b->m.planes[i].m.userptr, b->type, i);
+ return -EINVAL;
+ }
+ }
+
+ if (!buffer_info && inst->map_output_buffer) {
+ dprintk(VIDC_ERR,
+ "%s: error - no buffer info found in registered list\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ if (!buffer_info)
+ return -EINVAL;
+
+ buffer_info->dequeued = true;
+
+ dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+ buffer_info->fd[0]);
+ rc = unmap_and_deregister_buf(inst, buffer_info);
+ } else
+ rc = output_buffer_cache_invalidate(inst, buffer_info);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqbuf);
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamon(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamon(instance, i);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamon);
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst)
+ return -EINVAL;
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamoff(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamoff(instance, i);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamoff);
+
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_core_capability *capability = NULL;
+
+ if (!inst || !fsize) {
+ dprintk(VIDC_ERR, "%s: invalid parameter: %p %p\n",
+ __func__, inst, fsize);
+ return -EINVAL;
+ }
+ if (!inst->core)
+ return -EINVAL;
+
+ capability = &inst->capability;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = capability->width.min;
+ fsize->stepwise.max_width = capability->width.max;
+ fsize->stepwise.step_width = capability->width.step_size;
+ fsize->stepwise.min_height = capability->height.min;
+ fsize->stepwise.max_height = capability->height.max;
+ fsize->stepwise.step_height = capability->height.step_size;
+ return 0;
+}
+EXPORT_SYMBOL(msm_vidc_enum_framesizes);
+
+static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, enum dma_data_direction dma_dir)
+{
+ return (void *)0xdeadbeef;
+}
+
+static void vidc_put_userptr(void *buf_priv)
+{
+}
+
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+ .get_userptr = vidc_get_userptr,
+ .put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+ enum v4l2_buf_type type, enum session_type sess)
+{
+ struct vb2_queue *q = NULL;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+ } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+ } else {
+ dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
+ return -EINVAL;
+ }
+
+ q->type = type;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_flags = 0;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+ if (sess == MSM_VIDC_DECODER)
+ q->ops = msm_vdec_get_vb2q_ops();
+ else if (sess == MSM_VIDC_ENCODER)
+ q->ops = msm_venc_get_vb2q_ops();
+ //q->mem_ops = &msm_vidc_vb2_mem_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->drv_priv = inst;
+ return vb2_queue_init(q);
+}
+
+static int setup_event_queue(void *inst,
+ struct video_device *pvdev)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+ v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+ v4l2_fh_add(&vidc_inst->event_handler);
+
+ return rc;
+}
+
+int msm_vidc_subscribe_event(void *inst, const struct v4l2_event_subscription *sub)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+ if (!inst || !sub)
+ return -EINVAL;
+
+ rc = v4l2_event_subscribe(&vidc_inst->event_handler, sub, MAX_EVENTS, NULL);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vidc_subscribe_event);
+
+int msm_vidc_unsubscribe_event(void *inst, const struct v4l2_event_subscription *sub)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+ if (!inst || !sub)
+ return -EINVAL;
+
+ rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vidc_unsubscribe_event);
+
+int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+ if (!inst || !event)
+ return -EINVAL;
+
+ rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqevent);
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+ struct msm_vidc_inst *inst = NULL;
+ struct msm_vidc_core *core = NULL;
+ int rc = 0;
+ int i = 0;
+ if (core_id >= MSM_VIDC_CORES_MAX ||
+ session_type >= MSM_VIDC_MAX_DEVICES) {
+ dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n",
+ core_id, session_type);
+ goto err_invalid_core;
+ }
+ core = get_vidc_core(core_id);
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Failed to find core for core_id = %d\n", core_id);
+ goto err_invalid_core;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ dprintk(VIDC_ERR, "Failed to allocate memory\n");
+ rc = -ENOMEM;
+ goto err_invalid_core;
+ }
+
+ pr_info(VIDC_DBG_TAG "Opening video instance: %p, %d\n",
+ VIDC_MSG_PRIO2STRING(VIDC_INFO), inst, session_type);
+ mutex_init(&inst->sync_lock);
+ mutex_init(&inst->bufq[CAPTURE_PORT].lock);
+ mutex_init(&inst->bufq[OUTPUT_PORT].lock);
+ mutex_init(&inst->lock);
+
+ INIT_MSM_VIDC_LIST(&inst->pendingq);
+ INIT_MSM_VIDC_LIST(&inst->internalbufs);
+ INIT_MSM_VIDC_LIST(&inst->persistbufs);
+ INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
+ INIT_MSM_VIDC_LIST(&inst->outputbufs);
+ INIT_MSM_VIDC_LIST(&inst->registeredbufs);
+
+ inst->session_type = session_type;
+ inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+ inst->core = core;
+ inst->map_output_buffer = false;
+
+ for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+ i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+ init_completion(&inst->completions[i]);
+ }
+ inst->mem_client = msm_smem_new_client(SMEM_DMA,
+ &inst->core->resources);
+ if (!inst->mem_client) {
+ dprintk(VIDC_ERR, "Failed to create memory client\n");
+ goto fail_mem_client;
+ }
+ if (session_type == MSM_VIDC_DECODER) {
+ msm_vdec_inst_init(inst);
+ msm_vdec_ctrl_init(inst);
+ } else if (session_type == MSM_VIDC_ENCODER) {
+ msm_venc_inst_init(inst);
+ msm_venc_ctrl_init(inst);
+ }
+ msm_dcvs_init(inst);
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ session_type);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to initialize vb2 queue on capture port\n");
+ goto fail_bufq_capture;
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ session_type);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to initialize vb2 queue on capture port\n");
+ goto fail_bufq_output;
+ }
+
+ mutex_lock(&core->lock);
+ list_add_tail(&inst->list, &core->instances);
+ mutex_unlock(&core->lock);
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move video instance to init state\n");
+ goto fail_init;
+ }
+ inst->debugfs_root =
+ msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
+
+ setup_event_queue(inst, &core->vdev[session_type].vdev);
+
+ return inst;
+fail_init:
+ vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+
+ mutex_lock(&core->lock);
+ list_del(&inst->list);
+ mutex_unlock(&core->lock);
+
+fail_bufq_output:
+ vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+ if (session_type == MSM_VIDC_DECODER)
+ msm_vdec_ctrl_deinit(inst);
+ else if (session_type == MSM_VIDC_ENCODER)
+ msm_venc_ctrl_deinit(inst);
+ msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+ kfree(inst);
+ inst = NULL;
+err_invalid_core:
+ return inst;
+}
+EXPORT_SYMBOL(msm_vidc_open);
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+ struct vb2_buf_entry *entry, *dummy;
+ if (inst) {
+
+ mutex_lock(&inst->pendingq.lock);
+ list_for_each_entry_safe(entry, dummy, &inst->pendingq.list,
+ list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ mutex_unlock(&inst->pendingq.lock);
+
+ if (msm_comm_release_scratch_buffers(inst, false)) {
+ dprintk(VIDC_ERR,
+ "Failed to release scratch buffers\n");
+ }
+
+ if (msm_comm_release_persist_buffers(inst)) {
+ dprintk(VIDC_ERR,
+ "Failed to release persist buffers\n");
+ }
+
+ if (msm_comm_release_output_buffers(inst)) {
+ dprintk(VIDC_ERR,
+ "Failed to release output buffers\n");
+ }
+
+ if (inst->extradata_handle)
+ msm_comm_smem_free(inst, inst->extradata_handle);
+
+ debugfs_remove_recursive(inst->debugfs_root);
+
+ mutex_lock(&inst->pending_getpropq.lock);
+ WARN_ON(!list_empty(&inst->pending_getpropq.list));
+ mutex_unlock(&inst->pending_getpropq.lock);
+ }
+}
+
+int msm_vidc_close(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_inst *temp, *inst_dummy;
+ struct msm_vidc_core *core;
+ struct buffer_info *bi, *dummy;
+ int rc = 0;
+ int i;
+
+ if (!inst || !inst->core)
+ return -EINVAL;
+
+ v4l2_fh_del(&inst->event_handler);
+ v4l2_fh_exit(&inst->event_handler);
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ list_del(&bi->list);
+
+ for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+ i++) {
+ if (bi->handle[i])
+ msm_comm_smem_free(inst, bi->handle[i]);
+ }
+
+ kfree(bi);
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+
+ core = inst->core;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry_safe(temp, inst_dummy, &core->instances, list) {
+ if (temp == inst)
+ list_del(&inst->list);
+ }
+ mutex_unlock(&core->lock);
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ msm_vdec_ctrl_deinit(inst);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ msm_venc_ctrl_deinit(inst);
+
+ for (i = 0; i < MAX_PORT_NUM; i++)
+ vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
+ cleanup_instance(inst);
+ if (inst->state != MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID)
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+ else
+ rc = msm_comm_force_cleanup(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move video instance to uninit state\n");
+
+ msm_comm_session_clean(inst);
+
+ msm_smem_delete_client(inst->mem_client);
+
+ pr_info(VIDC_DBG_TAG "Closed video instance: %p\n",
+ VIDC_MSG_PRIO2STRING(VIDC_INFO), inst);
+ kfree(inst);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_vidc_close);
+
+int msm_vidc_suspend(int core_id)
+{
+ return msm_comm_suspend(core_id);
+}
+EXPORT_SYMBOL(msm_vidc_suspend);
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
new file mode 100644
index 000000000000..82bd7ab772e3
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -0,0 +1,4328 @@
+/* Copyright (c) 2012-2015, 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/jiffies.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <asm/div64.h>
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+ int __rc = (__p >= __d);\
+ __rc; \
+})
+
+#define IS_VALID_DCVS_SESSION(__cur_mbpf, __min_mbpf) \
+ ((__cur_mbpf) >= (__min_mbpf))
+
+#define SUM_ARRAY(__arr, __start, __end) ({\
+ int __index;\
+ typeof((__arr)[0]) __sum = 0;\
+ for (__index = (__start); __index <= (__end); __index++) {\
+ if (__index >= 0 && __index < ARRAY_SIZE(__arr))\
+ __sum += __arr[__index];\
+ } \
+ __sum;\
+})
+
+#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \
+ V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
+#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
+ V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+ V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
+
+#define IS_SESSION_CMD_VALID(cmd) (((cmd) >= SESSION_MSG_START) && \
+ ((cmd) <= SESSION_MSG_END))
+#define IS_SYS_CMD_VALID(cmd) (((cmd) >= SYS_MSG_START) && \
+ ((cmd) <= SYS_MSG_END))
+
+struct getprop_buf {
+ struct list_head list;
+ void *data;
+};
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
+static void handle_session_error(enum command_response cmd, void *data);
+
+static inline bool is_turbo_session(struct msm_vidc_inst *inst)
+{
+ return !!(inst->flags & VIDC_TURBO);
+}
+
+static inline bool is_thumbnail_session(struct msm_vidc_inst *inst)
+{
+ return !!(inst->flags & VIDC_THUMBNAIL);
+}
+
+static inline bool is_nominal_session(struct msm_vidc_inst *inst)
+{
+ return !!(inst->flags & VIDC_NOMINAL);
+}
+
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ int rc = 0;
+ struct v4l2_control ctrl = {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE
+ };
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl);
+ if (!rc && ctrl.value)
+ return HAL_VIDEO_DECODER_SECONDARY;
+ }
+ return HAL_VIDEO_DECODER_PRIMARY;
+}
+
+static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
+{
+ int output_port_mbs, capture_port_mbs;
+ output_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[OUTPUT_PORT],
+ inst->prop.height[OUTPUT_PORT]);
+ capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT]);
+ return max(output_port_mbs, capture_port_mbs) * inst->prop.fps;
+}
+
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks)
+{
+ int load = 0;
+ if (!(inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_STOP_DONE))
+ return 0;
+
+ load = msm_comm_get_mbs_per_sec(inst);
+
+ if (is_thumbnail_session(inst)) {
+ if (quirks & LOAD_CALC_IGNORE_THUMBNAIL_LOAD)
+ load = 0;
+ }
+
+ if (is_turbo_session(inst)) {
+ if (!(quirks & LOAD_CALC_IGNORE_TURBO_LOAD))
+ load = inst->core->resources.max_load;
+ }
+
+ return load;
+}
+
+int msm_comm_get_load(struct msm_vidc_core *core,
+ enum session_type type, enum load_calc_quirks quirks)
+{
+ struct msm_vidc_inst *inst = NULL;
+ int num_mbs_per_sec = 0;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "Invalid args: %p\n", core);
+ return -EINVAL;
+ }
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->session_type != type)
+ continue;
+
+ num_mbs_per_sec += msm_comm_get_inst_load(inst, quirks);
+ }
+ mutex_unlock(&core->lock);
+
+ return num_mbs_per_sec;
+}
+
+static enum hal_domain get_hal_domain(int session_type)
+{
+ enum hal_domain domain;
+ switch (session_type) {
+ case MSM_VIDC_ENCODER:
+ domain = HAL_VIDEO_DOMAIN_ENCODER;
+ break;
+ case MSM_VIDC_DECODER:
+ domain = HAL_VIDEO_DOMAIN_DECODER;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Wrong domain\n");
+ domain = HAL_UNUSED_DOMAIN;
+ break;
+ }
+
+ return domain;
+}
+
+enum hal_video_codec get_hal_codec_type(int fourcc)
+{
+ enum hal_video_codec codec;
+ dprintk(VIDC_DBG, "codec is %#x\n", fourcc);
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_H264_NO_SC:
+ codec = HAL_VIDEO_CODEC_H264;
+ break;
+ case V4L2_PIX_FMT_H264_MVC:
+ codec = HAL_VIDEO_CODEC_MVC;
+ break;
+ case V4L2_PIX_FMT_H263:
+ codec = HAL_VIDEO_CODEC_H263;
+ break;
+ case V4L2_PIX_FMT_MPEG1:
+ codec = HAL_VIDEO_CODEC_MPEG1;
+ break;
+ case V4L2_PIX_FMT_MPEG2:
+ codec = HAL_VIDEO_CODEC_MPEG2;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ codec = HAL_VIDEO_CODEC_MPEG4;
+ break;
+ case V4L2_PIX_FMT_VC1_ANNEX_G:
+ case V4L2_PIX_FMT_VC1_ANNEX_L:
+ codec = HAL_VIDEO_CODEC_VC1;
+ break;
+ case V4L2_PIX_FMT_VP8:
+ codec = HAL_VIDEO_CODEC_VP8;
+ break;
+ case V4L2_PIX_FMT_DIVX_311:
+ codec = HAL_VIDEO_CODEC_DIVX_311;
+ break;
+ case V4L2_PIX_FMT_DIVX:
+ codec = HAL_VIDEO_CODEC_DIVX;
+ break;
+ case V4L2_PIX_FMT_HEVC:
+ codec = HAL_VIDEO_CODEC_HEVC;
+ break;
+ case V4L2_PIX_FMT_HEVC_HYBRID:
+ codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
+ codec = HAL_UNUSED_CODEC;
+ break;
+ }
+
+ return codec;
+}
+
+static int msm_comm_vote_bus(struct msm_vidc_core *core)
+{
+ int rc = 0, vote_data_count = 0, i = 0;
+ struct hfi_device *hdev;
+ struct msm_vidc_inst *inst = NULL;
+ struct vidc_bus_vote_data *vote_data = NULL;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, core);
+ return -EINVAL;
+ }
+
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s Invalid device handle: %p\n",
+ __func__, hdev);
+ return -EINVAL;
+ }
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list)
+ ++vote_data_count;
+
+ vote_data = kzalloc(sizeof(*vote_data) * vote_data_count,
+ GFP_TEMPORARY);
+ if (!vote_data) {
+ dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ list_for_each_entry(inst, &core->instances, list) {
+ int codec = 0;
+
+ codec = inst->session_type == MSM_VIDC_DECODER ?
+ inst->fmts[OUTPUT_PORT]->fourcc :
+ inst->fmts[CAPTURE_PORT]->fourcc;
+
+ vote_data[i].session = VIDC_VOTE_DATA_SESSION_VAL(
+ get_hal_codec_type(codec),
+ get_hal_domain(inst->session_type));
+ vote_data[i].load = msm_comm_get_inst_load(inst,
+ LOAD_CALC_NO_QUIRKS);
+ i++;
+ }
+ mutex_unlock(&core->lock);
+
+ rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, vote_data,
+ vote_data_count);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+
+ kfree(vote_data);
+ return rc;
+
+fail_alloc:
+ mutex_unlock(&core->lock);
+ return rc;
+}
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+ struct msm_vidc_core *core;
+ int found = 0;
+ if (core_id > MSM_VIDC_CORES_MAX) {
+ dprintk(VIDC_ERR, "Core id = %d is greater than max = %d\n",
+ core_id, MSM_VIDC_CORES_MAX);
+ return NULL;
+ }
+ mutex_lock(&vidc_driver->lock);
+ list_for_each_entry(core, &vidc_driver->cores, list) {
+ if (core->id == core_id) {
+ found = 1;
+ break;
+ }
+ }
+ mutex_unlock(&vidc_driver->lock);
+ if (found)
+ return core;
+ return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+ int i, k = 0;
+ if (!fmt || index < 0) {
+ dprintk(VIDC_ERR, "Invalid inputs, fmt = %p, index = %d\n",
+ fmt, index);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].type != fmt_type)
+ continue;
+ if (k == index)
+ break;
+ k++;
+ }
+ if (i == size) {
+ dprintk(VIDC_INFO, "Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+ int i;
+ if (!fmt) {
+ dprintk(VIDC_ERR, "Invalid inputs, fmt = %p\n", fmt);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].fourcc == fourcc)
+ break;
+ }
+ if (i == size) {
+ dprintk(VIDC_INFO, "Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+
+struct buf_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return &inst->bufq[CAPTURE_PORT];
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return &inst->bufq[OUTPUT_PORT];
+ return NULL;
+}
+
+static void handle_sys_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core;
+ struct vidc_hal_sys_init_done *sys_init_msg;
+ unsigned int index;
+
+ if (!IS_SYS_CMD_VALID(cmd)) {
+ dprintk(VIDC_ERR, "%s - invalid cmd\n", __func__);
+ return;
+ }
+ index = SYS_MSG_INDEX(cmd);
+
+ if (!response) {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for sys init\n");
+ return;
+ }
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ dprintk(VIDC_ERR, "Wrong device_id received\n");
+ return;
+ }
+ sys_init_msg = response->data;
+ if (!sys_init_msg) {
+ dprintk(VIDC_ERR, "sys_init_done message not proper\n");
+ return;
+ }
+ core->enc_codec_supported = sys_init_msg->enc_codec_supported;
+ core->dec_codec_supported = sys_init_msg->dec_codec_supported;
+ if (core->id == MSM_VIDC_CORE_VENUS &&
+ (core->dec_codec_supported & HAL_VIDEO_CODEC_H264))
+ core->dec_codec_supported |=
+ HAL_VIDEO_CODEC_MVC;
+ dprintk(VIDC_DBG, "supported_codecs: enc = %#x, dec = %#x\n",
+ core->enc_codec_supported, core->dec_codec_supported);
+ dprintk(VIDC_DBG, "ptr[%d] = %p\n", index, &(core->completions[index]));
+ complete(&(core->completions[index]));
+}
+
+static void handle_session_release_buf_done(enum command_response cmd,
+ void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct internal_buf *buf;
+ struct list_head *ptr, *next;
+ struct hal_buffer_info *buffer;
+ u32 buf_found = false;
+ u32 address;
+
+ if (!response || !response->data) {
+ dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+ buffer = (struct hal_buffer_info *) response->data;
+ address = buffer->buffer_addr;
+
+ mutex_lock(&inst->internalbufs.lock);
+ list_for_each_safe(ptr, next, &inst->internalbufs.list) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == (u32)buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing scratch: %pa\n",
+ &buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+ mutex_unlock(&inst->internalbufs.lock);
+
+ mutex_lock(&inst->persistbufs.lock);
+ list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == (u32)buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing persist: %pa\n",
+ &buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+ mutex_unlock(&inst->persistbufs.lock);
+
+ if (!buf_found)
+ dprintk(VIDC_ERR, "invalid buffer received from firmware");
+ if (IS_SESSION_CMD_VALID(cmd)) {
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+ } else {
+ dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+ return;
+ }
+}
+
+static void handle_sys_release_res_done(
+ enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core;
+ if (!response) {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for sys init\n");
+ return;
+ }
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ dprintk(VIDC_ERR, "Wrong device_id received\n");
+ return;
+ }
+ complete(&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
+}
+
+static void change_inst_state(struct msm_vidc_inst *inst,
+ enum instance_state state)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid parameter %s\n", __func__);
+ return;
+ }
+ mutex_lock(&inst->lock);
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_DBG,
+ "Inst: %p is in bad state can't change state\n",
+ inst);
+ goto exit;
+ }
+ dprintk(VIDC_DBG, "Moved inst: %p from state: %d to state: %d\n",
+ inst, inst->state, state);
+ inst->state = state;
+exit:
+ mutex_unlock(&inst->lock);
+}
+
+static int signal_session_msg_receipt(enum command_response cmd,
+ struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid(%p) instance id\n", inst);
+ return -EINVAL;
+ }
+ if (IS_SESSION_CMD_VALID(cmd)) {
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+ } else {
+ dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+ enum command_response cmd)
+{
+ int rc = 0;
+
+ if (!IS_SESSION_CMD_VALID(cmd)) {
+ dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+ return -EINVAL;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(cmd)],
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR, "Wait interrupted or timedout: %d\n", rc);
+ msm_comm_kill_session(inst);
+ rc = -EIO;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+ enum instance_state flipped_state,
+ enum instance_state desired_state,
+ enum command_response hal_cmd)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto err_same_state;
+ }
+ dprintk(VIDC_DBG, "Waiting for hal_cmd: %d\n", hal_cmd);
+ rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+ if (!rc)
+ change_inst_state(inst, desired_state);
+err_same_state:
+ return rc;
+}
+
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+{
+ struct v4l2_event event = {.id = 0, .type = event_type};
+ v4l2_event_queue_fh(&inst->event_handler, &event);
+}
+
+static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
+{
+ enum command_response cmd = SESSION_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+ return;
+ }
+ dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
+ response.session_id = inst;
+ response.status = VIDC_ERR_MAX_CLIENTS;
+ handle_session_error(cmd, (void *)&response);
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst = NULL;
+ struct hfi_device *hdev;
+
+ if (response) {
+ struct vidc_hal_session_init_done *session_init_done =
+ (struct vidc_hal_session_init_done *)
+ response->data;
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid parameters (%p)\n",
+ __func__, inst);
+ return;
+ }
+
+ hdev = inst->core->device;
+
+ if (!response->status && session_init_done) {
+ inst->capability.width = session_init_done->width;
+ inst->capability.height = session_init_done->height;
+ inst->capability.frame_rate =
+ session_init_done->frame_rate;
+ inst->capability.scale_x = session_init_done->scale_x;
+ inst->capability.scale_y = session_init_done->scale_y;
+ inst->capability.hier_p = session_init_done->hier_p;
+ inst->capability.ltr_count =
+ session_init_done->ltr_count;
+ inst->capability.pixelprocess_capabilities =
+ call_hfi_op(hdev, get_core_capabilities);
+ inst->capability.mbs_per_frame =
+ session_init_done->mbs_per_frame;
+ inst->capability.capability_set = true;
+ inst->capability.buffer_mode[CAPTURE_PORT] =
+ session_init_done->alloc_mode_out;
+ inst->capability.secure_output2_threshold =
+ session_init_done->secure_output2_threshold;
+ } else {
+ dprintk(VIDC_ERR,
+ "Session init response from FW : %#x\n",
+ response->status);
+ if (response->status == VIDC_ERR_MAX_CLIENTS)
+ msm_comm_generate_max_clients_error(inst);
+ else
+ msm_comm_generate_session_error(inst);
+ }
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session init\n");
+ }
+}
+
+static void handle_event_change(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct v4l2_control control = {0};
+ struct msm_vidc_cb_event *event_notify;
+ int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ int rc = 0;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ event_notify = (struct msm_vidc_cb_event *) response->data;
+ switch (event_notify->hal_event_type) {
+ case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to get Smooth streamng flag\n");
+ if (!rc && control.value == true)
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ break;
+ case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ break;
+ case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+ {
+ struct v4l2_event buf_event = {0};
+ struct buffer_info *binfo = NULL, *temp = NULL;
+ u32 *ptr = NULL;
+
+ dprintk(VIDC_DBG,
+ "%s - inst: %p buffer: %pa extra: %pa\n",
+ __func__, inst, &event_notify->packet_buffer,
+ &event_notify->extra_data_buffer);
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_DBG,
+ "Event release buf ref received in invalid state - discard\n");
+ return;
+ }
+
+ /*
+ * Get the buffer_info entry for the
+ * device address.
+ */
+ binfo = device_to_uvaddr(&inst->registeredbufs,
+ event_notify->packet_buffer);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+
+ /* Fill event data to be sent to client*/
+ buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+
+ dprintk(VIDC_DBG,
+ "RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
+ ptr[0], ptr[1]);
+
+ mutex_lock(&inst->sync_lock);
+
+ /* Decrement buffer reference count*/
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list,
+ list) {
+ if (temp == binfo) {
+ buf_ref_put(inst, binfo);
+ break;
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+
+ /*
+ * Release buffer and remove from list
+ * if reference goes to zero.
+ */
+ if (unmap_and_deregister_buf(inst, binfo))
+ dprintk(VIDC_ERR,
+ "%s: buffer unmap failed\n", __func__);
+ mutex_unlock(&inst->sync_lock);
+
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler, &buf_event);
+ return;
+ }
+ default:
+ break;
+ }
+ if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
+ inst->reconfig_height = event_notify->height;
+ inst->reconfig_width = event_notify->width;
+ inst->in_reconfig = true;
+ } else {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
+ if (msm_comm_get_stream_output_mode(inst) !=
+ HAL_VIDEO_DECODER_SECONDARY) {
+ dprintk(VIDC_DBG,
+ "event_notify->height = %d event_notify->width = %d\n",
+ event_notify->height,
+ event_notify->width);
+ inst->prop.height[CAPTURE_PORT] =
+ event_notify->height;
+ inst->prop.width[CAPTURE_PORT] =
+ event_notify->width;
+ inst->prop.height[OUTPUT_PORT] =
+ event_notify->height;
+ inst->prop.width[OUTPUT_PORT] =
+ event_notify->width;
+ }
+ }
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ msm_dcvs_init_load(inst);
+ rc = msm_vidc_check_session_supported(inst);
+ if (!rc) {
+ msm_vidc_queue_v4l2_event(inst, event);
+ } else if (rc == -ENOTSUPP) {
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED);
+ } else if (rc == -EBUSY) {
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
+ }
+
+ return;
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for event_change\n");
+ }
+}
+
+static void handle_session_prop_info(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct getprop_buf *getprop;
+ struct msm_vidc_inst *inst;
+ if (!response || !response->data) {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for prop info\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+
+ getprop = kzalloc(sizeof(*getprop), GFP_KERNEL);
+ if (!getprop) {
+ dprintk(VIDC_ERR, "%s: getprop kzalloc failed\n", __func__);
+ return;
+ }
+
+ getprop->data = kmemdup(response->data, response->size, GFP_KERNEL);
+ if (!getprop->data) {
+ dprintk(VIDC_ERR, "%s: kmemdup failed\n", __func__);
+ kfree(getprop);
+ return;
+ }
+
+ mutex_lock(&inst->pending_getpropq.lock);
+ list_add_tail(&getprop->list, &inst->pending_getpropq.list);
+ mutex_unlock(&inst->pending_getpropq.lock);
+
+ signal_session_msg_receipt(cmd, inst);
+ return;
+}
+
+static void handle_load_resource_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (response->status) {
+ dprintk(VIDC_ERR,
+ "Load resource response from FW : %#x\n",
+ response->status);
+ msm_comm_generate_session_error(inst);
+ }
+ } else
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for load resource\n");
+}
+
+static void handle_start_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for start\n");
+ }
+}
+
+static void handle_stop_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for stop\n");
+ }
+}
+
+static void handle_release_res_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for release resource\n");
+ }
+}
+void validate_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct internal_buf *binfo;
+ u32 buffers_owned_by_driver = 0;
+ struct hal_buffer_requirements *output_buf;
+ output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_OUTPUT);
+ return;
+ }
+ mutex_lock(&inst->outputbufs.lock);
+ list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+ if (binfo->buffer_ownership != DRIVER) {
+ dprintk(VIDC_DBG,
+ "This buffer is with FW %pa\n",
+ &binfo->handle->device_addr);
+ continue;
+ }
+ buffers_owned_by_driver++;
+ }
+ mutex_unlock(&inst->outputbufs.lock);
+
+ if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+ dprintk(VIDC_WARN,
+ "OUTPUT Buffer count mismatch %d of %d\n",
+ buffers_owned_by_driver,
+ output_buf->buffer_count_actual);
+
+ return;
+}
+
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct internal_buf *binfo;
+ struct hfi_device *hdev;
+ struct msm_smem *handle;
+ struct vidc_frame_data frame_data = {0};
+ struct hal_buffer_requirements *output_buf;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_OUTPUT);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "output: num = %d, size = %d\n",
+ output_buf->buffer_count_actual,
+ output_buf->buffer_size);
+
+ mutex_lock(&inst->outputbufs.lock);
+ list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+ if (binfo->buffer_ownership != DRIVER)
+ continue;
+ handle = binfo->handle;
+ frame_data.alloc_len = output_buf->buffer_size;
+ frame_data.filled_len = 0;
+ frame_data.offset = 0;
+ frame_data.device_addr = handle->device_addr;
+ frame_data.flags = 0;
+ frame_data.extradata_addr = handle->device_addr +
+ output_buf->buffer_size;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = call_hfi_op(hdev, session_ftb,
+ (void *) inst->session, &frame_data);
+ binfo->buffer_ownership = FIRMWARE;
+ }
+ mutex_unlock(&inst->outputbufs.lock);
+
+ return 0;
+}
+
+static void handle_session_flush(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ int rc;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ validate_output_buffers(inst);
+ if (!inst->in_reconfig) {
+ rc = msm_comm_queue_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to queue output buffers: %d\n",
+ rc);
+ }
+ }
+ }
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+ } else {
+ dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
+ }
+}
+
+static void handle_session_error(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct hfi_device *hdev = NULL;
+ struct msm_vidc_inst *inst = NULL;
+
+ if (!response) {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session error\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+
+ if (!inst || !inst->session || !inst->core->device) {
+ dprintk(VIDC_ERR,
+ "Session (%p) not in a stable enough state to handle session error\n",
+ inst);
+ return;
+ }
+
+ hdev = inst->core->device;
+ dprintk(VIDC_WARN, "Session error received for session %p\n", inst);
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+
+ if (response->status == VIDC_ERR_MAX_CLIENTS) {
+ dprintk(VIDC_WARN,
+ "send max clients reached error to client: %p\n",
+ inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
+ } else {
+ dprintk(VIDC_ERR,
+ "send session error to client: %p\n",
+ inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ }
+}
+
+static void msm_comm_clean_notify_client(struct msm_vidc_core *core)
+{
+ struct msm_vidc_inst *inst = NULL;
+ if (!core) {
+ dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+ return;
+ }
+
+ dprintk(VIDC_WARN, "%s: Core %p\n", __func__, core);
+ mutex_lock(&core->lock);
+ core->state = VIDC_CORE_INVALID;
+
+ list_for_each_entry(inst, &core->instances, list) {
+ mutex_lock(&inst->lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->lock);
+ dprintk(VIDC_WARN,
+ "%s Send sys error for inst %p\n", __func__, inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ }
+ mutex_unlock(&core->lock);
+}
+
+struct sys_err_handler_data {
+ struct msm_vidc_core *core;
+ struct delayed_work work;
+};
+
+
+void hw_sys_error_handler(struct work_struct *work)
+{
+ struct msm_vidc_core *core = NULL;
+ struct hfi_device *hdev = NULL;
+ struct sys_err_handler_data *handler = NULL;
+ int rc = 0;
+
+ handler = container_of(work, struct sys_err_handler_data, work.work);
+ if (!handler || !handler->core || !handler->core->device) {
+ dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+ __func__);
+ goto exit;
+ }
+
+ core = handler->core;
+ hdev = core->device;
+
+ mutex_lock(&core->lock);
+ /*
+ * Restart the firmware to bring out of bad state.
+ */
+ if (core->state == VIDC_CORE_INVALID && hdev->resurrect_fw) {
+ rc = call_hfi_op(hdev, resurrect_fw,
+ hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s - resurrect_fw failed: %d\n",
+ __func__, rc);
+ }
+ core->state = VIDC_CORE_LOADED;
+ } else {
+ dprintk(VIDC_DBG,
+ "fw unloaded after sys error, no need to resurrect\n");
+ }
+ mutex_unlock(&core->lock);
+
+exit:
+ /* free sys error handler, allocated in handle_sys_err */
+ kfree(handler);
+}
+
+static void handle_sys_error(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core = NULL;
+ struct sys_err_handler_data *handler = NULL;
+
+ subsystem_crashed("venus");
+ if (!response) {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for sys error\n");
+ return;
+ }
+
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Got SYS_ERR but unable to identify core\n");
+ return;
+ }
+
+ dprintk(VIDC_WARN, "SYS_ERROR %d received for core %p\n", cmd, core);
+ msm_comm_clean_notify_client(core);
+
+ handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+ if (!handler) {
+ dprintk(VIDC_ERR,
+ "%s - failed to allocate sys error handler\n",
+ __func__);
+ return;
+ }
+ handler->core = core;
+ INIT_DELAYED_WORK(&handler->work, hw_sys_error_handler);
+
+ /*
+ * Sleep for 5 sec to ensure venus has completed any
+ * pending cache operations. Without this sleep, we see
+ * device reset when firmware is unloaded after a sys
+ * error.
+ */
+ schedule_delayed_work(&handler->work, msecs_to_jiffies(5000));
+}
+
+void msm_comm_session_clean(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev = NULL;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return;
+ }
+
+ hdev = inst->core->device;
+ mutex_lock(&inst->lock);
+ if (hdev && inst->session) {
+ dprintk(VIDC_DBG, "cleaning up instance: %p\n", inst);
+ rc = call_hfi_op(hdev, session_clean,
+ (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session clean failed :%p\n", inst);
+ }
+ inst->session = NULL;
+ }
+ mutex_unlock(&inst->lock);
+}
+
+static void handle_session_close(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return;
+ }
+ signal_session_msg_receipt(cmd, inst);
+ show_stats(inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session close\n");
+ }
+}
+
+static struct vb2_buffer *get_vb_from_v4l2_index(struct msm_vidc_inst* inst,
+ struct buf_queue *bufq, unsigned long dev_addr)
+{
+
+ struct vb2_buffer *vb = NULL;
+ struct vb2_queue *q = NULL;
+ struct buffer_info* binfo = NULL;
+ int found = 0, plane = 0;
+ if (!inst || !bufq) {
+ dprintk(VIDC_ERR, "Invalid parameter\n");
+ return NULL;
+ }
+ q = &bufq->vb2_bufq;
+ mutex_lock(&bufq->lock);
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ binfo = get_registered_mmap_buf(inst, &vb->v4l2_buf, &plane);
+ if (binfo != NULL && binfo->device_addr[plane] == dev_addr) {
+ found = 1;
+ dprintk(VIDC_DBG, "Found v4l2_buf idx %d, addr %#lx\n",
+ vb->v4l2_buf.index, dev_addr);
+ break;
+ }
+ }
+ mutex_unlock(&bufq->lock);
+ if (!found) {
+ dprintk(VIDC_DBG,
+ "Failed to find buffer in queued list: %#lx, qtype = %d\n",
+ dev_addr, q->type);
+ vb = NULL;
+ }
+ return vb;
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
+ unsigned long dev_addr)
+{
+ struct vb2_buffer *vb = NULL;
+ struct vb2_queue *q = NULL;
+ int found = 0;
+ if (!bufq) {
+ dprintk(VIDC_ERR, "Invalid parameter\n");
+ return NULL;
+ }
+ q = &bufq->vb2_bufq;
+ mutex_lock(&bufq->lock);
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->v4l2_planes[0].m.userptr == dev_addr &&
+ vb->state == VB2_BUF_STATE_ACTIVE) {
+ found = 1;
+ dprintk(VIDC_DBG, "Found v4l2_buf index : %d\n",
+ vb->v4l2_buf.index);
+ break;
+ }
+ }
+ mutex_unlock(&bufq->lock);
+ if (!found) {
+ dprintk(VIDC_DBG,
+ "Failed to find buffer in queued list: %#lx, qtype = %d\n",
+ dev_addr, q->type);
+ vb = NULL;
+ }
+ return vb;
+}
+
+static void handle_ebd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct vb2_buffer *vb;
+ struct msm_vidc_inst *inst;
+ struct vidc_hal_ebd *empty_buf_done;
+
+ if (!response) {
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid response from vidc_hal\n",
+ __func__);
+ return;
+ }
+ if (inst->bufq[OUTPUT_PORT].vb2_bufq.memory == V4L2_MEMORY_MMAP) {
+ vb = get_vb_from_v4l2_index(inst, &inst->bufq[OUTPUT_PORT],
+ response->clnt_data);
+ } else {
+ vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT],
+ response->clnt_data);
+ }
+ if (vb) {
+ vb->v4l2_planes[0].bytesused = response->input_done.filled_len;
+ vb->v4l2_planes[0].data_offset = response->input_done.offset;
+ if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO, "data_offset overflow length\n");
+ if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO, "bytesused overflow length\n");
+ if (vb->v4l2_buf.memory == V4L2_MEMORY_USERPTR &&
+ vb->v4l2_planes[0].m.userptr !=
+ response->input_done.packet_buffer)
+ dprintk(VIDC_INFO, "Unexpected buffer address\n");
+ empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
+ if (empty_buf_done) {
+ if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
+ dprintk(VIDC_INFO,
+ "Failed : Unsupported input stream\n");
+ vb->v4l2_buf.flags |=
+ V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
+ }
+ if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) {
+ dprintk(VIDC_INFO,
+ "Failed : Corrupted input stream\n");
+ vb->v4l2_buf.flags |=
+ V4L2_QCOM_BUF_DATA_CORRUPT;
+ }
+ if (empty_buf_done->status ==
+ VIDC_ERR_START_CODE_NOT_FOUND) {
+ vb->v4l2_buf.flags |=
+ V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND;
+ dprintk(VIDC_INFO,
+ "Failed: Start code not found\n");
+ }
+ }
+ dprintk(VIDC_DBG,
+ "Got ebd from hal: device_addr: %pa, alloc: %d, status: %#x, pic_type: %#x, flags: %#x\n",
+ &empty_buf_done->packet_buffer,
+ empty_buf_done->alloc_len, empty_buf_done->status,
+ empty_buf_done->picture_type, empty_buf_done->flags);
+
+ mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
+ msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD);
+ }
+}
+
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int cnt = 0;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ atomic_inc(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ if (cnt > 2) {
+ dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+ dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+
+ return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int rc = 0;
+ int cnt;
+ bool release_buf = false;
+ bool qbuf_again = false;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ atomic_dec(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+ if (!cnt)
+ release_buf = true;
+ else if (cnt == 1)
+ qbuf_again = true;
+ else {
+ dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+
+ if (cnt < 0)
+ return cnt;
+
+ rc = output_buffer_cache_invalidate(inst, binfo);
+ if (rc)
+ return rc;
+
+ if (release_buf) {
+ /*
+ * We can not delete binfo here as we need to set the user
+ * virtual address saved in binfo->uvaddr to the dequeued v4l2
+ * buffer.
+ *
+ * We will set the pending_deletion flag to true here and delete
+ * binfo from registered list in dqbuf after setting the uvaddr.
+ */
+ dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+ binfo->fd[0]);
+ binfo->pending_deletion = true;
+ } else if (qbuf_again) {
+ rc = qbuf_dynamic_buf(inst, binfo);
+ if (!rc)
+ return rc;
+ }
+ return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+ ion_phys_addr_t device_addr, u32 flags)
+{
+ struct buffer_info *binfo = NULL, *temp = NULL;
+
+ /*
+ * Update reference count and release OR queue back the buffer,
+ * only when firmware is not holding a reference.
+ */
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ binfo = device_to_uvaddr(&inst->registeredbufs, device_addr);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+ if (flags & HAL_BUFFERFLAG_READONLY) {
+ dprintk(VIDC_DBG,
+ "FBD fd[0] = %d -> Reference with f/w, addr: %pa\n",
+ binfo->fd[0], &device_addr);
+ } else {
+ dprintk(VIDC_DBG,
+ "FBD fd[0] = %d -> FBD_ref_released, addr: %pa\n",
+ binfo->fd[0], &device_addr);
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list,
+ list) {
+ if (temp == binfo) {
+ buf_ref_put(inst, binfo);
+ break;
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+ }
+ }
+}
+
+static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
+ ion_phys_addr_t dev_addr)
+{
+ struct internal_buf *binfo;
+ struct msm_smem *handle;
+ bool found = false;
+
+ mutex_lock(&inst->outputbufs.lock);
+ list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+ handle = binfo->handle;
+ if (handle && dev_addr == handle->device_addr) {
+ if (binfo->buffer_ownership == DRIVER) {
+ dprintk(VIDC_ERR,
+ "FW returned same buffer: %pa\n",
+ &dev_addr);
+ break;
+ }
+ binfo->buffer_ownership = DRIVER;
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&inst->outputbufs.lock);
+
+ if (!found) {
+ dprintk(VIDC_ERR,
+ "Failed to find output buffer in queued list: %pa\n",
+ &dev_addr);
+ }
+
+ return 0;
+}
+
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
+{
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY)
+ return HAL_BUFFER_OUTPUT2;
+ else
+ return HAL_BUFFER_OUTPUT;
+}
+
+static void handle_fbd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb = NULL;
+ struct vidc_hal_fbd *fill_buf_done;
+ enum hal_buffer buffer_type;
+ int extra_idx = 0;
+ int64_t time_usec = 0;
+
+ if (!response) {
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ buffer_type = msm_comm_get_hal_output_buffer(inst);
+ if (fill_buf_done->buffer_type == buffer_type) {
+ if (inst->bufq[CAPTURE_PORT].vb2_bufq.memory == V4L2_MEMORY_MMAP) {
+ vb = get_vb_from_v4l2_index(inst, &inst->bufq[CAPTURE_PORT],
+ fill_buf_done->packet_buffer1);
+ } else {
+ vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+ fill_buf_done->packet_buffer1);
+ }
+ } else {
+ if (handle_multi_stream_buffers(inst,
+ fill_buf_done->packet_buffer1))
+ dprintk(VIDC_ERR,
+ "Failed : Output buffer not found %pa\n",
+ &fill_buf_done->packet_buffer1);
+ return;
+ }
+ if (vb) {
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
+ vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
+ vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
+ vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
+ vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
+ vb->v4l2_planes[0].reserved[6] =
+ inst->prop.width[CAPTURE_PORT];
+ vb->v4l2_planes[0].reserved[7] =
+ inst->prop.height[CAPTURE_PORT];
+ if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO,
+ "fbd:Overflow data_offset = %d; length = %d\n",
+ vb->v4l2_planes[0].data_offset,
+ vb->v4l2_planes[0].length);
+ if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO,
+ "fbd:Overflow bytesused = %d; length = %d\n",
+ vb->v4l2_planes[0].bytesused,
+ vb->v4l2_planes[0].length);
+ if (!(fill_buf_done->flags1 &
+ HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
+ fill_buf_done->filled_len1) {
+ time_usec = fill_buf_done->timestamp_hi;
+ time_usec = (time_usec << 32) |
+ fill_buf_done->timestamp_lo;
+ } else {
+ time_usec = 0;
+ dprintk(VIDC_DBG,
+ "Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
+ &fill_buf_done->packet_buffer1,
+ fill_buf_done->filled_len1,
+ fill_buf_done->timestamp_hi,
+ fill_buf_done->timestamp_lo);
+ }
+ vb->v4l2_buf.timestamp =
+ ns_to_timeval(time_usec * NSEC_PER_USEC);
+ vb->v4l2_buf.flags = 0;
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+ vb->v4l2_planes[extra_idx].m.userptr =
+ (unsigned long)fill_buf_done->extra_data_buffer;
+ vb->v4l2_planes[extra_idx].bytesused =
+ vb->v4l2_planes[extra_idx].length;
+ vb->v4l2_planes[extra_idx].data_offset = 0;
+ }
+
+ handle_dynamic_buffer(inst, fill_buf_done->packet_buffer1,
+ fill_buf_done->flags1);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOS;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+ vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DROP_FRAME;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_MBAFF)
+ vb->v4l2_buf.flags |= V4L2_MSM_BUF_FLAG_MBAFF;
+ if (fill_buf_done->flags1 &
+ HAL_BUFFERFLAG_TS_DISCONTINUITY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_TS_DISCONTINUITY;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_TS_ERROR)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_TS_ERROR;
+ switch (fill_buf_done->picture_type) {
+ case HAL_PICTURE_IDR:
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case HAL_PICTURE_I:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case HAL_PICTURE_P:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case HAL_PICTURE_B:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ case HAL_FRAME_NOTCODED:
+ case HAL_UNUSED_PICT:
+ /* Do we need to care about these? */
+ case HAL_FRAME_YUV:
+ break;
+ default:
+ break;
+ }
+ inst->count.fbd++;
+ if (fill_buf_done->filled_len1)
+ msm_vidc_debugfs_update(inst,
+ MSM_VIDC_DEBUGFS_EVENT_FBD);
+
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+ dprintk(VIDC_DBG,
+ "extradata: userptr = %p;"
+ " bytesused = %d; length = %d\n",
+ (u8 *)vb->v4l2_planes[extra_idx].m.userptr,
+ vb->v4l2_planes[extra_idx].bytesused,
+ vb->v4l2_planes[extra_idx].length);
+ }
+ dprintk(VIDC_DBG,
+ "Got fbd from hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: %#x, crop: %d %d %d %d, pic_type: %#x\n",
+ &fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
+ fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
+ fill_buf_done->flags1, fill_buf_done->start_x_coord,
+ fill_buf_done->start_y_coord, fill_buf_done->frame_width,
+ fill_buf_done->frame_height, fill_buf_done->picture_type);
+
+ mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+ }
+}
+
+static void handle_seq_hdr_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb;
+ struct vidc_hal_fbd *fill_buf_done;
+ if (!response) {
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+ fill_buf_done->packet_buffer1);
+ if (!vb) {
+ dprintk(VIDC_ERR,
+ "Failed to find video buffer for seq_hdr_done\n");
+ return;
+ }
+
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
+
+ vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+ vb->v4l2_buf.timestamp = ns_to_timeval(0);
+
+ dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
+ vb->v4l2_planes[0].bytesused,
+ vb->v4l2_planes[0].data_offset,
+ vb->v4l2_buf.flags);
+ mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+}
+
+void handle_cmd_response(enum command_response cmd, void *data)
+{
+ dprintk(VIDC_DBG, "Command response = %d\n", cmd);
+ switch (cmd) {
+ case SYS_INIT_DONE:
+ handle_sys_init_done(cmd, data);
+ break;
+ case RELEASE_RESOURCE_DONE:
+ handle_sys_release_res_done(cmd, data);
+ break;
+ case SESSION_INIT_DONE:
+ handle_session_init_done(cmd, data);
+ break;
+ case SESSION_PROPERTY_INFO:
+ handle_session_prop_info(cmd, data);
+ break;
+ case SESSION_LOAD_RESOURCE_DONE:
+ handle_load_resource_done(cmd, data);
+ break;
+ case SESSION_START_DONE:
+ handle_start_done(cmd, data);
+ break;
+ case SESSION_ETB_DONE:
+ handle_ebd(cmd, data);
+ break;
+ case SESSION_FTB_DONE:
+ handle_fbd(cmd, data);
+ break;
+ case SESSION_STOP_DONE:
+ handle_stop_done(cmd, data);
+ break;
+ case SESSION_RELEASE_RESOURCE_DONE:
+ handle_release_res_done(cmd, data);
+ break;
+ case SESSION_END_DONE:
+ case SESSION_ABORT_DONE:
+ handle_session_close(cmd, data);
+ break;
+ case VIDC_EVENT_CHANGE:
+ handle_event_change(cmd, data);
+ break;
+ case SESSION_FLUSH_DONE:
+ handle_session_flush(cmd, data);
+ break;
+ case SESSION_GET_SEQ_HDR_DONE:
+ handle_seq_hdr_done(cmd, data);
+ break;
+ case SYS_WATCHDOG_TIMEOUT:
+ handle_sys_error(cmd, data);
+ break;
+ case SYS_ERROR:
+ handle_sys_error(cmd, data);
+ break;
+ case SESSION_ERROR:
+ handle_session_error(cmd, data);
+ break;
+ case SESSION_RELEASE_BUFFER_DONE:
+ handle_session_release_buf_done(cmd, data);
+ break;
+ default:
+ dprintk(VIDC_DBG, "response unhandled: %d\n", cmd);
+ break;
+ }
+}
+
+int msm_comm_scale_clocks(struct msm_vidc_core *core)
+{
+ int num_mbs_per_sec =
+ msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS) +
+ msm_comm_get_load(core, MSM_VIDC_DECODER, LOAD_CALC_NO_QUIRKS);
+ return msm_comm_scale_clocks_load(core, num_mbs_per_sec);
+}
+
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core, int num_mbs_per_sec)
+{
+ u32 codecs_enabled = 0;
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct msm_vidc_inst *inst = NULL;
+ bool is_nominal = false;
+ struct msm_vidc_platform_resources *res;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, core);
+ return -EINVAL;
+ }
+
+ hdev = core->device;
+ res = &core->resources;
+
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s Invalid device handle: %p\n",
+ __func__, hdev);
+ return -EINVAL;
+ }
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ int codec = 0;
+
+ codec = inst->session_type == MSM_VIDC_DECODER ?
+ inst->fmts[OUTPUT_PORT]->fourcc :
+ inst->fmts[CAPTURE_PORT]->fourcc;
+
+ codecs_enabled |= VIDC_VOTE_DATA_SESSION_VAL(
+ get_hal_codec_type(codec),
+ get_hal_domain(inst->session_type));
+
+ if (is_nominal_session(inst))
+ is_nominal = true;
+ }
+ mutex_unlock(&core->lock);
+
+ dprintk(VIDC_INFO, "num_mbs_per_sec = %d codecs_enabled %#x\n",
+ num_mbs_per_sec, codecs_enabled);
+
+ if (is_nominal && num_mbs_per_sec) {
+ struct load_freq_table *table = res->load_freq_tbl;
+ u32 table_size = res->load_freq_tbl_size;
+ u32 low_freq = table[table_size - 1].freq;
+ int i;
+
+ /*
+ * Parse the load frequency table from highest index and
+ * whenever there is a change in frequency detected, it is
+ * assumed as nominal frequency Check the current load
+ * against the load corresponding to nominal frequency and
+ * update num_mbs_per_sec accordingly.
+ */
+ for (i = table_size - 1; i >= 0; i--) {
+ if (table[i].freq > low_freq) {
+ if (num_mbs_per_sec < table[i].load) {
+ num_mbs_per_sec = table[i].load;
+ dprintk(VIDC_DBG,
+ "updated num_mbs_per_sec: %d\n",
+ num_mbs_per_sec);
+ }
+ break;
+ }
+ }
+ }
+
+ rc = call_hfi_op(hdev, scale_clocks,
+ hdev->hfi_device_data, num_mbs_per_sec, codecs_enabled);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
+ return rc;
+}
+
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return;
+ }
+ core = inst->core;
+ hdev = core->device;
+
+ if (msm_comm_scale_clocks(core)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Performance might be impacted\n");
+ }
+ if (msm_comm_vote_bus(core)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale DDR bus. Performance might be impacted\n");
+ }
+}
+
+static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level)
+{
+ switch (level) {
+ case 0:
+ return VIDC_THERMAL_NORMAL;
+ case 1:
+ return VIDC_THERMAL_LOW;
+ case 2:
+ return VIDC_THERMAL_HIGH;
+ default:
+ return VIDC_THERMAL_CRITICAL;
+ }
+}
+
+static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core)
+{
+ struct hfi_device *hdev;
+ unsigned long freq = 0;
+
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ hdev = core->device;
+
+ freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data);
+ dprintk(VIDC_DBG, "clock freq %ld\n", freq);
+
+ return freq;
+}
+
+static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq)
+{
+ int i = 0;
+ struct msm_vidc_platform_resources *res = &core->resources;
+ struct load_freq_table *table = res->load_freq_tbl;
+ u32 max_freq = 0;
+
+ for (i = 0; i < res->load_freq_tbl_size; i++) {
+ if (max_freq < table[i].freq)
+ max_freq = table[i].freq;
+ }
+ return freq >= max_freq;
+}
+
+static bool is_thermal_permissible(struct msm_vidc_core *core)
+{
+ enum msm_vidc_thermal_level tl;
+ unsigned long freq = 0;
+ bool is_turbo = false;
+
+ if (!core->resources.thermal_mitigable)
+ return true;
+
+ if (msm_vidc_thermal_mitigation_disabled) {
+ dprintk(VIDC_DBG,
+ "Thermal mitigation not enabled. debugfs %d\n",
+ msm_vidc_thermal_mitigation_disabled);
+ return true;
+ }
+
+ tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level);
+ freq = msm_comm_get_clock_rate(core);
+
+ is_turbo = is_core_turbo(core, freq);
+ dprintk(VIDC_DBG,
+ "Core freq %ld Thermal level %d Turbo mode %d\n",
+ freq, tl, is_turbo);
+
+ if (is_turbo && tl >= VIDC_THERMAL_LOW) {
+ dprintk(VIDC_ERR,
+ "Video session not allowed. Turbo mode %d Thermal level %d\n",
+ is_turbo, tl);
+ return false;
+ }
+ return true;
+}
+
+static int msm_comm_session_abort(struct msm_vidc_inst *inst)
+{
+ int rc = 0, abort_completion = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ rc = call_hfi_op(hdev, session_abort, (void *)inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s session_abort failed rc: %d\n", __func__, rc);
+ return rc;
+ }
+ abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE);
+ init_completion(&inst->completions[abort_completion]);
+ rc = wait_for_completion_timeout(
+ &inst->completions[abort_completion],
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "%s: Wait interrupted or timed out [%p]: %d\n",
+ __func__, inst, abort_completion);
+ rc = -EBUSY;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static void handle_thermal_event(struct msm_vidc_core *core)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst;
+
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return;
+ }
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (!inst->session)
+ continue;
+
+ mutex_unlock(&core->lock);
+ if (inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_CLOSE_DONE) {
+ dprintk(VIDC_WARN, "%s: abort inst %p\n",
+ __func__, inst);
+ rc = msm_comm_session_abort(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s session_abort failed rc: %d\n",
+ __func__, rc);
+ goto err_sess_abort;
+ }
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+ dprintk(VIDC_WARN,
+ "%s Send sys error for inst %p\n",
+ __func__, inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ } else {
+ msm_comm_generate_session_error(inst);
+ }
+ mutex_lock(&core->lock);
+ }
+ mutex_unlock(&core->lock);
+ return;
+
+err_sess_abort:
+ msm_comm_clean_notify_client(core);
+ return;
+}
+
+void msm_comm_handle_thermal_event()
+{
+ struct msm_vidc_core *core;
+
+ list_for_each_entry(core, &vidc_driver->cores, list) {
+ if (!is_thermal_permissible(core)) {
+ dprintk(VIDC_WARN,
+ "Thermal level critical, stop all active sessions!\n");
+ handle_thermal_event(core);
+ }
+ }
+}
+
+int msm_comm_check_core_init(struct msm_vidc_core *core)
+{
+ int rc = 0;
+
+ mutex_lock(&core->lock);
+ if (core->state >= VIDC_CORE_INIT_DONE) {
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto exit;
+ }
+ dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
+ rc = wait_for_completion_timeout(
+ &core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
+ __func__, SYS_MSG_INDEX(SYS_INIT_DONE));
+ rc = -EIO;
+ goto exit;
+ } else {
+ core->state = VIDC_CORE_INIT_DONE;
+ rc = 0;
+ }
+ dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
+exit:
+ mutex_unlock(&core->lock);
+ return rc;
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+
+ rc = msm_comm_check_core_init(inst->core);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to initialize core\n", __func__);
+ return rc;
+ }
+ change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ return rc;
+}
+
+int msm_comm_load_fw(struct msm_vidc_core *core)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!core || !core->device)
+ return -EINVAL;
+ hdev = core->device;
+
+ mutex_lock(&core->lock);
+ if (core->state >= VIDC_CORE_INIT) {
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+
+ if (core->state < VIDC_CORE_LOADED) {
+ rc = call_hfi_op(hdev, load_fw, hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load video firmware\n");
+ mutex_unlock(&core->lock);
+ goto fail_load_fw;
+ }
+ core->state = VIDC_CORE_LOADED;
+ dprintk(VIDC_DBG, "Firmware downloaded\n");
+ }
+
+ if (core->state == VIDC_CORE_LOADED) {
+ init_completion(&core->completions
+ [SYS_MSG_INDEX(SYS_INIT_DONE)]);
+ rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
+ core->id);
+ mutex_unlock(&core->lock);
+ goto fail_core_init;
+ }
+ core->state = VIDC_CORE_INIT;
+ }
+
+core_already_inited:
+ mutex_unlock(&core->lock);
+ return rc;
+
+fail_core_init:
+ mutex_lock(&core->lock);
+ call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
+ core->state = VIDC_CORE_UNINIT;
+ mutex_unlock(&core->lock);
+fail_load_fw:
+ return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+
+ if (!inst || !inst->core)
+ return -EINVAL;
+
+ rc = msm_comm_load_fw(inst->core);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - firmware loading failed\n", __func__);
+ return rc;
+ }
+
+ change_inst_state(inst, MSM_VIDC_CORE_INIT);
+ return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ hdev = core->device;
+
+ mutex_lock(&core->lock);
+ if (core->state == VIDC_CORE_UNINIT) {
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_uninited;
+ }
+ mutex_unlock(&core->lock);
+
+ msm_comm_scale_clocks_and_bus(inst);
+
+ mutex_lock(&core->lock);
+
+ /*
+ * If firmware is configured to be always loaded in memory,
+ * then unload it only if the core has gone in to bad state.
+ */
+ if (core->resources.early_fw_load &&
+ core->state != VIDC_CORE_INVALID) {
+ goto core_already_uninited;
+ }
+
+ if (list_empty(&core->instances)) {
+ cancel_delayed_work(&core->fw_unload_work);
+
+ /*
+ * Delay unloading of firmware. This is useful
+ * in avoiding firmware download delays in cases where we
+ * will have a burst of back to back video playback sessions
+ * e.g. thumbnail generation.
+ */
+#if 0
+ schedule_delayed_work(&core->fw_unload_work,
+ msecs_to_jiffies(core->state == VIDC_CORE_INVALID ?
+ 0 : msm_vidc_firmware_unload_delay));
+
+ dprintk(VIDC_DBG, "firmware unload delayed by %u ms\n",
+ core->state == VIDC_CORE_INVALID ?
+ 0 : msm_vidc_firmware_unload_delay);
+#endif
+ }
+
+core_already_uninited:
+ change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+ mutex_unlock(&core->lock);
+ return 0;
+}
+
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst)
+{
+ return msm_vidc_deinit_core(inst);
+}
+
+static int msm_comm_session_init(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int fourcc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+ } else {
+ dprintk(VIDC_ERR, "Invalid session\n");
+ return -EINVAL;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+
+ inst->session = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
+ inst, get_hal_domain(inst->session_type),
+ get_hal_codec_type(fourcc));
+
+ if (!inst->session) {
+ dprintk(VIDC_ERR,
+ "Failed to call session init for: %p, %p, %d, %d\n",
+ inst->core->device, inst,
+ inst->session_type, fourcc);
+ rc = -EINVAL;
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+static void msm_vidc_print_running_insts(struct msm_vidc_core *core)
+{
+ struct msm_vidc_inst *temp;
+ dprintk(VIDC_ERR, "Running instances:\n");
+ dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s|%4s\n",
+ "type", "w", "h", "fps", "prop");
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(temp, &core->instances, list) {
+ if (temp->state >= MSM_VIDC_OPEN_DONE &&
+ temp->state < MSM_VIDC_STOP_DONE) {
+ char properties[4] = "";
+
+ if (is_thumbnail_session(temp))
+ strlcat(properties, "N", sizeof(properties));
+
+ if (is_turbo_session(temp))
+ strlcat(properties, "T", sizeof(properties));
+
+ dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4s\n",
+ temp->session_type,
+ max(temp->prop.width[CAPTURE_PORT],
+ temp->prop.width[OUTPUT_PORT]),
+ max(temp->prop.height[CAPTURE_PORT],
+ temp->prop.height[OUTPUT_PORT]),
+ temp->prop.fps, properties);
+ }
+ }
+ mutex_unlock(&core->lock);
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ int num_mbs_per_sec = 0;
+ struct msm_vidc_core *core;
+ enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+ LOAD_CALC_IGNORE_THUMBNAIL_LOAD;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ if (core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't do load res\n");
+ return -EINVAL;
+ }
+
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Instance is in invalid state can't do load res\n");
+ return -EINVAL;
+ }
+
+ num_mbs_per_sec =
+ msm_comm_get_load(core, MSM_VIDC_DECODER, quirks) +
+ msm_comm_get_load(core, MSM_VIDC_ENCODER, quirks);
+
+ if (num_mbs_per_sec > core->resources.max_load) {
+ dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+ num_mbs_per_sec, core->resources.max_load);
+ msm_vidc_print_running_insts(core);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_kill_session(inst);
+ return -EBUSY;
+ }
+
+ hdev = core->device;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+
+ rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't do start\n");
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
+ rc = call_hfi_op(hdev, session_start, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to send start\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_START);
+exit:
+ return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ dprintk(VIDC_DBG, "Send Stop to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
+ rc = call_hfi_op(hdev, session_stop, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to send stop\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+ return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ dprintk(VIDC_DBG,
+ "Send release res to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
+ rc = call_hfi_op(hdev, session_release_res, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to send release resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_comm_session_close(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
+ goto exit;
+ }
+ dprintk(VIDC_DBG,
+ "Send session close to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
+ rc = call_hfi_op(hdev, session_end, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to send close\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_CLOSE);
+exit:
+ return rc;
+}
+
+int msm_comm_suspend(int core_id)
+{
+ struct hfi_device *hdev;
+ struct msm_vidc_core *core;
+ int rc = 0;
+
+ core = get_vidc_core(core_id);
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to find core for core_id = %d\n",
+ __func__, core_id);
+ return -EINVAL;
+ }
+
+ hdev = (struct hfi_device *)core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s Invalid device handle\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
+ if (rc)
+ dprintk(VIDC_WARN, "Failed to suspend\n");
+
+ return rc;
+}
+
+static int get_flipped_state(int present_state,
+ int desired_state)
+{
+ int flipped_state = present_state;
+ if (flipped_state < MSM_VIDC_STOP
+ && desired_state > MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ } else if (flipped_state > MSM_VIDC_STOP
+ && desired_state < MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP -
+ (flipped_state - MSM_VIDC_STOP + 1);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ }
+ return flipped_state;
+}
+
+struct hal_buffer_requirements *get_buff_req_buffer(
+ struct msm_vidc_inst *inst, enum hal_buffer buffer_type)
+{
+ int i;
+ for (i = 0; i < HAL_BUFFER_MAX; i++) {
+ if (inst->buff_req.buffer[i].buffer_type == buffer_type)
+ return &inst->buff_req.buffer[i];
+ }
+ return NULL;
+}
+
+static int set_output_buffers(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info = {0};
+ u32 smem_flags = 0, buffer_size;
+ struct hal_buffer_requirements *output_buf, *extradata_buf;
+ int i;
+ struct hfi_device *hdev;
+
+ hdev = inst->core->device;
+
+ output_buf = get_buff_req_buffer(inst, buffer_type);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ buffer_type);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "output: num = %d, size = %d\n",
+ output_buf->buffer_count_actual,
+ output_buf->buffer_size);
+
+ buffer_size = output_buf->buffer_size;
+
+ extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (extradata_buf) {
+ dprintk(VIDC_DBG,
+ "extradata: num = %d, size = %d\n",
+ extradata_buf->buffer_count_actual,
+ extradata_buf->buffer_size);
+ buffer_size += extradata_buf->buffer_size;
+ } else {
+ dprintk(VIDC_DBG,
+ "This extradata buffer not required, buffer_type: %x\n",
+ buffer_type);
+ }
+
+ if (inst->flags & VIDC_SECURE)
+ smem_flags |= SMEM_SECURE;
+
+ if (output_buf->buffer_size) {
+ for (i = 0; i < output_buf->buffer_count_actual;
+ i++) {
+ handle = msm_comm_smem_alloc(inst,
+ buffer_size, 1, smem_flags,
+ buffer_type, 0);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate output memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ rc = msm_comm_smem_cache_operations(inst,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto fail_kzalloc;
+ }
+
+ binfo->handle = handle;
+ buffer_info.buffer_size = output_buf->buffer_size;
+ buffer_info.buffer_type = buffer_type;
+ binfo->buffer_type = buffer_type;
+ buffer_info.num_buffers = 1;
+ binfo->buffer_ownership = DRIVER;
+ buffer_info.align_device_addr = handle->device_addr;
+ buffer_info.extradata_addr = handle->device_addr +
+ output_buf->buffer_size;
+ if (extradata_buf) {
+ buffer_info.extradata_size =
+ extradata_buf->buffer_size;
+ }
+ dprintk(VIDC_DBG, "Output buffer address: %pa\n",
+ &buffer_info.align_device_addr);
+ dprintk(VIDC_DBG, "Output extradata address: %pa\n",
+ &buffer_info.extradata_addr);
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *) inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : session_set_buffers failed\n",
+ __func__);
+ goto fail_set_buffers;
+ }
+ mutex_lock(&inst->outputbufs.lock);
+ list_add_tail(&binfo->list, &inst->outputbufs.list);
+ mutex_unlock(&inst->outputbufs.lock);
+ }
+ }
+ return rc;
+fail_set_buffers:
+ kfree(binfo);
+fail_kzalloc:
+ msm_comm_smem_free(inst, handle);
+err_no_mem:
+ return rc;
+}
+
+static inline char *get_internal_buffer_name(enum hal_buffer buffer_type)
+{
+ switch (buffer_type) {
+ case HAL_BUFFER_INTERNAL_SCRATCH: return "scratch";
+ case HAL_BUFFER_INTERNAL_SCRATCH_1: return "scratch_1";
+ case HAL_BUFFER_INTERNAL_SCRATCH_2: return "scratch_2";
+ case HAL_BUFFER_INTERNAL_PERSIST: return "persist";
+ case HAL_BUFFER_INTERNAL_PERSIST_1: return "persist_1";
+ default: return "unknown";
+ }
+}
+
+static int set_internal_buf_on_fw(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type,
+ struct msm_smem *handle, bool reuse)
+{
+ struct vidc_buffer_addr_info buffer_info;
+ struct hfi_device *hdev;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device || !handle) {
+ dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
+ rc = msm_comm_smem_cache_operations(inst,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache. May cause undefined behavior\n");
+ }
+
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = buffer_type;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ dprintk(VIDC_DBG, "%s %s buffer : %pa\n",
+ reuse ? "Reusing" : "Allocated",
+ get_internal_buffer_name(buffer_type),
+ &buffer_info.align_device_addr);
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *) inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
+ return rc;
+ }
+ return 0;
+}
+
+static bool reuse_scratch_buffers(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ struct internal_buf *buf;
+ int rc = 0;
+ bool reused = false;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
+ return false;
+ }
+
+ mutex_lock(&inst->internalbufs.lock);
+ list_for_each_entry(buf, &inst->internalbufs.list, list) {
+ if (!buf->handle) {
+ reused = false;
+ break;
+ }
+
+ if (buf->buffer_type != buffer_type)
+ continue;
+
+ rc = set_internal_buf_on_fw(inst, buffer_type,
+ buf->handle, true);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session_set_buffers failed\n", __func__);
+ reused = false;
+ break;
+ }
+ reused = true;
+ }
+ mutex_unlock(&inst->internalbufs.lock);
+ return reused;
+}
+
+static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
+ struct hal_buffer_requirements *internal_bufreq,
+ struct msm_vidc_list *buf_list)
+{
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ u32 smem_flags = 0;
+ int rc = 0;
+ int i = 0;
+
+ if (!inst || !internal_bufreq || !buf_list)
+ return -EINVAL;
+
+ if (!internal_bufreq->buffer_size)
+ return 0;
+
+ if (inst->flags & VIDC_SECURE)
+ smem_flags |= SMEM_SECURE;
+
+ for (i = 0; i < internal_bufreq->buffer_count_actual; i++) {
+ handle = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size,
+ 1, smem_flags, internal_bufreq->buffer_type, 0);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate scratch memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto fail_kzalloc;
+ }
+
+ binfo->handle = handle;
+ binfo->buffer_type = internal_bufreq->buffer_type;
+
+ rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type,
+ handle, false);
+ if (rc)
+ goto fail_set_buffers;
+
+ mutex_lock(&buf_list->lock);
+ list_add_tail(&binfo->list, &buf_list->list);
+ mutex_unlock(&buf_list->lock);
+ }
+ return rc;
+
+fail_set_buffers:
+ kfree(binfo);
+fail_kzalloc:
+ msm_comm_smem_free(inst, handle);
+err_no_mem:
+ return rc;
+
+}
+
+static int set_scratch_buffers(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ struct hal_buffer_requirements *scratch_buf;
+
+ scratch_buf = get_buff_req_buffer(inst, buffer_type);
+ if (!scratch_buf) {
+ dprintk(VIDC_DBG,
+ "This scratch buffer not required, buffer_type: %x\n",
+ buffer_type);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "scratch: num = %d, size = %d\n",
+ scratch_buf->buffer_count_actual,
+ scratch_buf->buffer_size);
+
+ /*
+ * Try reusing existing scratch buffers first.
+ * If it's not possible to reuse, allocate new buffers.
+ */
+ if (reuse_scratch_buffers(inst, buffer_type))
+ return 0;
+
+ return allocate_and_set_internal_bufs(inst, scratch_buf,
+ &inst->internalbufs);
+}
+
+static int set_persist_buffers(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ struct hal_buffer_requirements *persist_buf;
+
+ persist_buf = get_buff_req_buffer(inst, buffer_type);
+ if (!persist_buf) {
+ dprintk(VIDC_DBG,
+ "This persist buffer not required, buffer_type: %x\n",
+ buffer_type);
+ return 0;
+ }
+
+ dprintk(VIDC_DBG, "persist: num = %d, size = %d\n",
+ persist_buf->buffer_count_actual,
+ persist_buf->buffer_size);
+
+ mutex_lock(&inst->persistbufs.lock);
+ if (!list_empty(&inst->persistbufs.list)) {
+ dprintk(VIDC_ERR, "Persist buffers already allocated\n");
+ mutex_unlock(&inst->persistbufs.lock);
+ return 0;
+ }
+ mutex_unlock(&inst->persistbufs.lock);
+
+ return allocate_and_set_internal_bufs(inst, persist_buf,
+ &inst->persistbufs);
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+ int rc = 0;
+ int flipped_state;
+ struct msm_vidc_core *core;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG,
+ "Trying to move inst: %p from: %#x to %#x\n",
+ inst, inst->state, state);
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ mutex_lock(&inst->sync_lock);
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't change the state\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ flipped_state = get_flipped_state(inst->state, state);
+ dprintk(VIDC_DBG,
+ "flipped_state = %#x\n", flipped_state);
+ switch (flipped_state) {
+ case MSM_VIDC_CORE_UNINIT_DONE:
+ case MSM_VIDC_CORE_INIT:
+ rc = msm_comm_init_core(inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_CORE_INIT_DONE:
+ rc = msm_comm_init_core_done(inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_OPEN:
+ rc = msm_comm_session_init(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_OPEN_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+ SESSION_INIT_DONE);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_LOAD_RESOURCES:
+ rc = msm_vidc_load_resources(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_LOAD_RESOURCES_DONE:
+ case MSM_VIDC_START:
+ rc = msm_vidc_start(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_START_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+ SESSION_START_DONE);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_STOP:
+ rc = msm_vidc_stop(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_STOP_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+ SESSION_STOP_DONE);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ dprintk(VIDC_DBG, "Moving to Stop Done state\n");
+ case MSM_VIDC_RELEASE_RESOURCES:
+ rc = msm_vidc_release_res(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_RELEASE_RESOURCES_DONE:
+ rc = wait_for_state(inst, flipped_state,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ SESSION_RELEASE_RESOURCE_DONE);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ dprintk(VIDC_DBG,
+ "Moving to release resources done state\n");
+ case MSM_VIDC_CLOSE:
+ rc = msm_comm_session_close(flipped_state, inst);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_CLOSE_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+ SESSION_END_DONE);
+ if (rc || state <= get_flipped_state(inst->state, state))
+ break;
+ case MSM_VIDC_CORE_UNINIT:
+ case MSM_VIDC_CORE_INVALID:
+ dprintk(VIDC_DBG, "Sending core uninit\n");
+ rc = msm_vidc_deinit_core(inst);
+ if (rc || state == get_flipped_state(inst->state, state))
+ break;
+ default:
+ dprintk(VIDC_ERR, "State %d not recognized\n", flipped_state);
+ rc = -EINVAL;
+ break;
+ }
+exit:
+ mutex_unlock(&inst->sync_lock);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move from state: %d to %d\n",
+ inst->state, state);
+ else
+ trace_msm_vidc_common_state_change((void *)inst,
+ inst->state, state);
+ return rc;
+}
+
+int msm_comm_qbuf(struct vb2_buffer *vb)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ struct msm_vidc_inst *inst;
+ struct vb2_buf_entry *entry;
+ struct vidc_frame_data frame_data;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ int extra_idx = 0, plane = 0;
+ struct buffer_info* binfo;
+ dma_addr_t device_addr;
+
+ if (!vb || !vb->vb2_queue) {
+ dprintk(VIDC_ERR, "%s: Invalid input: %p\n",
+ __func__, vb);
+ return -EINVAL;
+ }
+
+ q = vb->vb2_queue;
+ inst = q->drv_priv;
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: Invalid input: %p\n",
+ __func__, vb);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid input: %p, %p, %p\n", inst, core, vb);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s: Invalid input: %p\n",
+ __func__, hdev);
+ return -EINVAL;
+ }
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR, "Core is in bad state. Can't Queue\n");
+ return -EINVAL;
+ }
+ if (inst->state != MSM_VIDC_START_DONE) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ goto err_no_mem;
+ }
+ entry->vb = vb;
+
+ mutex_lock(&inst->pendingq.lock);
+ list_add_tail(&entry->list, &inst->pendingq.list);
+ mutex_unlock(&inst->pendingq.lock);
+ } else {
+ int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
+ if (vb->v4l2_buf.memory == V4L2_MEMORY_MMAP) {
+ binfo = get_registered_mmap_buf(
+ inst, &vb->v4l2_buf, &plane);
+ if (binfo == NULL) {
+ dprintk(VIDC_ERR, "unable to find binfo %d", vb->v4l2_buf.index);
+ rc = -EINVAL;
+ goto err_bad_input;
+ }
+ device_addr = binfo->device_addr[0];
+ } else {
+ device_addr = vb->v4l2_planes[0].m.userptr;
+ }
+ do_div(time_usec, NSEC_PER_USEC);
+ memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
+ frame_data.alloc_len = vb->v4l2_planes[0].length;
+ frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+ frame_data.offset = vb->v4l2_planes[0].data_offset;
+ frame_data.device_addr = device_addr;
+ frame_data.timestamp = time_usec;
+ frame_data.flags = 0;
+ frame_data.clnt_data = frame_data.device_addr;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ (frame_data.filled_len > frame_data.alloc_len ||
+ frame_data.offset > frame_data.alloc_len)) {
+ dprintk(VIDC_ERR,
+ "Buffer will overflow, not queueing it\n");
+ rc = -EINVAL;
+ goto err_bad_input;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ frame_data.buffer_type = HAL_BUFFER_INPUT;
+ if (vb->v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_EOS) {
+ frame_data.flags |= HAL_BUFFERFLAG_EOS;
+ dprintk(VIDC_DBG,
+ "Received EOS on output capability\n");
+ }
+
+ if (vb->v4l2_buf.flags &
+ V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP) {
+ frame_data.flags |=
+ HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP;
+ dprintk(VIDC_DBG,
+ "Received buff with 601to709 clamp\n");
+ }
+
+ if (vb->v4l2_buf.flags &
+ V4L2_QCOM_BUF_FLAG_CODECCONFIG) {
+ frame_data.flags |= HAL_BUFFERFLAG_CODECCONFIG;
+ dprintk(VIDC_DBG,
+ "Received CODECCONFIG on output cap\n");
+ }
+
+ if (vb->v4l2_buf.flags &
+ V4L2_QCOM_BUF_FLAG_DECODEONLY) {
+ frame_data.flags |= HAL_BUFFERFLAG_DECODEONLY;
+ dprintk(VIDC_DBG,
+ "Received DECODEONLY on output cap\n");
+ }
+
+ if (vb->v4l2_buf.flags &
+ V4L2_QCOM_BUF_TIMESTAMP_INVALID)
+ frame_data.timestamp = LLONG_MAX;
+
+ if (vb->v4l2_buf.flags &
+ V4L2_QCOM_BUF_TS_DISCONTINUITY) {
+ frame_data.flags |=
+ HAL_BUFFERFLAG_TS_DISCONTINUITY;
+ dprintk(VIDC_DBG,
+ "Received TS_DISCONTINUE on output\n");
+ }
+
+ if (vb->v4l2_buf.flags & V4L2_QCOM_BUF_TS_ERROR) {
+ frame_data.flags |=
+ HAL_BUFFERFLAG_TS_ERROR;
+ dprintk(VIDC_DBG,
+ "Received TS_ERROR on output cap\n");
+ }
+
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[OUTPUT_PORT]->
+ num_planes);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+ vb->v4l2_planes[extra_idx].m.userptr) {
+ frame_data.extradata_addr =
+ vb->v4l2_planes[extra_idx].m.userptr;
+ frame_data.flags |= HAL_BUFFERFLAG_EXTRADATA;
+ }
+
+ dprintk(VIDC_DBG,
+ "Sending etb to hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags = %#x, v4l2_buf index = %d\n",
+ &frame_data.device_addr, frame_data.alloc_len,
+ frame_data.filled_len, frame_data.offset,
+ frame_data.timestamp, frame_data.flags,
+ vb->v4l2_buf.index);
+
+ msm_dcvs_check_and_scale_clocks(inst, true);
+ rc = call_hfi_op(hdev, session_etb, (void *)
+ inst->session, &frame_data);
+ if (!rc)
+ msm_vidc_debugfs_update(inst,
+ MSM_VIDC_DEBUGFS_EVENT_ETB);
+ dprintk(VIDC_DBG, "Sent etb to HAL\n");
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct vidc_seq_hdr seq_hdr;
+ frame_data.filled_len = 0;
+ frame_data.offset = 0;
+ frame_data.alloc_len = vb->v4l2_planes[0].length;
+ frame_data.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
+
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+ vb->v4l2_planes[extra_idx].m.userptr) {
+ frame_data.extradata_addr =
+ vb->v4l2_planes[extra_idx].m.userptr;
+ frame_data.extradata_size =
+ vb->v4l2_planes[extra_idx].length;
+ }
+
+ dprintk(VIDC_DBG,
+ "Sending ftb to hal: device_addr: %pa, alloc: %d, buffer_type: %d, ts: %lld, flags = %#x, v4l2_buf index = %d\n",
+ &frame_data.device_addr, frame_data.alloc_len,
+ frame_data.buffer_type, frame_data.timestamp,
+ frame_data.flags, vb->v4l2_buf.index);
+
+ if (atomic_read(&inst->seq_hdr_reqs) &&
+ inst->session_type == MSM_VIDC_ENCODER) {
+ seq_hdr.seq_hdr = vb->v4l2_planes[0].
+ m.userptr;
+ seq_hdr.seq_hdr_len = vb->v4l2_planes[0].length;
+ rc = call_hfi_op(hdev, session_get_seq_hdr,
+ (void *) inst->session, &seq_hdr);
+ if (!rc) {
+ inst->vb2_seq_hdr = vb;
+ dprintk(VIDC_DBG, "Seq_hdr: %p\n",
+ inst->vb2_seq_hdr);
+ }
+ atomic_dec(&inst->seq_hdr_reqs);
+ } else {
+ msm_dcvs_check_and_scale_clocks(inst, false);
+ rc = call_hfi_op(hdev, session_ftb,
+ (void *) inst->session, &frame_data);
+ if (!rc)
+ msm_vidc_debugfs_update(inst,
+ MSM_VIDC_DEBUGFS_EVENT_FTB);
+ }
+ } else {
+ dprintk(VIDC_ERR,
+ "This capability is not supported: %d\n",
+ q->type);
+ rc = -EINVAL;
+ }
+ }
+err_bad_input:
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to queue buffer\n");
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+ struct buffer_requirements buf_req;
+ int rc = 0;
+ int i = 0;
+ union hal_get_property hprop;
+
+ rc = msm_comm_try_get_prop(inst,
+ HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+ &hprop);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s Error rc:%d\n", __func__, rc);
+ return rc;
+ }
+ buf_req = hprop.buf_req;
+ memcpy(&inst->buff_req, &buf_req,
+ sizeof(struct buffer_requirements));
+ for (i = 0; i < HAL_BUFFER_MAX; i++) {
+ dprintk(VIDC_DBG,
+ "buffer type: %d, count : %d, size: %d\n",
+ inst->buff_req.buffer[i].buffer_type,
+ inst->buff_req.buffer[i].buffer_count_actual,
+ inst->buff_req.buffer[i].buffer_size);
+ }
+ dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n",
+ inst->buff_req.buffer[0].buffer_count_actual,
+ inst->buff_req.buffer[1].buffer_count_actual);
+ return rc;
+}
+
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
+ union hal_get_property *hprop)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct getprop_buf *buf;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't query get_bufreqs()\n");
+ return -EAGAIN;
+ }
+ hdev = inst->core->device;
+ mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR,
+ "%s Not in proper state\n", __func__);
+ rc = -EAGAIN;
+ goto exit;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
+ switch (ptype) {
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ rc = call_hfi_op(hdev, session_get_property,
+ (void *) inst->session, ptype);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s Failed: PROFILE_LEVEL_INFO\n",
+ __func__);
+ rc = -EAGAIN;
+ goto exit;
+ }
+ break;
+ case HAL_PARAM_GET_BUFFER_REQUIREMENTS:
+ rc = call_hfi_op(hdev, session_get_buf_req,
+ (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get property\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
+ break;
+ default:
+ rc = -EAGAIN;
+ dprintk(VIDC_ERR, "%s id:%d not supported\n", __func__, ptype);
+ break;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "%s: Wait interrupted or timed out [%p]: %d\n",
+ __func__, inst,
+ SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_kill_session(inst);
+ rc = -EIO;
+ goto exit;
+ }
+
+ mutex_lock(&inst->pending_getpropq.lock);
+ if (!list_empty(&inst->pending_getpropq.list)) {
+ buf = list_first_entry(&inst->pending_getpropq.list,
+ struct getprop_buf, list);
+ *hprop = *((union hal_get_property *) buf->data);
+ kfree(buf->data);
+ list_del(&buf->list);
+ kfree(buf);
+ rc = 0;
+ } else {
+ dprintk(VIDC_ERR, "%s getprop list empty\n", __func__);
+ rc = -EINVAL;
+ }
+ mutex_unlock(&inst->pending_getpropq.lock);
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct internal_buf *buf, *dummy;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
+ mutex_lock(&inst->outputbufs.lock);
+ list_for_each_entry_safe(buf, dummy, &inst->outputbufs.list, list) {
+ handle = buf->handle;
+ if (!handle) {
+ dprintk(VIDC_ERR, "%s - invalid handle\n", __func__);
+ goto exit;
+ }
+
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = buf->buffer_type;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ if (inst->state != MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Rel output buf fail:%pa, %d\n",
+ &buffer_info.align_device_addr,
+ buffer_info.buffer_size);
+ }
+ }
+
+ list_del(&buf->list);
+ msm_comm_smem_free(inst, buf->handle);
+ kfree(buf);
+ }
+
+exit:
+ mutex_unlock(&inst->outputbufs.lock);
+ return rc;
+}
+
+static enum hal_buffer scratch_buf_sufficient(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ struct hal_buffer_requirements *bufreq = NULL;
+ struct internal_buf *buf;
+ int count = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+ goto not_sufficient;
+ }
+
+ bufreq = get_buff_req_buffer(inst, buffer_type);
+ if (!bufreq)
+ goto not_sufficient;
+
+ /* Check if current scratch buffers are sufficient */
+ mutex_lock(&inst->internalbufs.lock);
+
+ list_for_each_entry(buf, &inst->internalbufs.list, list) {
+ if (!buf->handle) {
+ dprintk(VIDC_ERR, "%s: invalid buf handle\n", __func__);
+ mutex_unlock(&inst->internalbufs.lock);
+ goto not_sufficient;
+ }
+ if (buf->buffer_type == buffer_type &&
+ buf->handle->size >= bufreq->buffer_size)
+ count++;
+ }
+ mutex_unlock(&inst->internalbufs.lock);
+
+ if (count != bufreq->buffer_count_actual)
+ goto not_sufficient;
+
+ dprintk(VIDC_DBG,
+ "Existing scratch buffer is sufficient for buffer type %#x\n",
+ buffer_type);
+
+ return buffer_type;
+
+not_sufficient:
+ return HAL_BUFFER_NONE;
+}
+
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+ bool check_for_reuse)
+{
+ struct msm_smem *handle;
+ struct internal_buf *buf, *dummy;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ enum hal_buffer sufficiency = HAL_BUFFER_NONE;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
+
+ if (check_for_reuse) {
+ sufficiency |= scratch_buf_sufficient(inst,
+ HAL_BUFFER_INTERNAL_SCRATCH);
+
+ sufficiency |= scratch_buf_sufficient(inst,
+ HAL_BUFFER_INTERNAL_SCRATCH_1);
+
+ sufficiency |= scratch_buf_sufficient(inst,
+ HAL_BUFFER_INTERNAL_SCRATCH_2);
+ }
+
+ mutex_lock(&inst->internalbufs.lock);
+ list_for_each_entry_safe(buf, dummy, &inst->internalbufs.list, list) {
+ if (!buf->handle) {
+ dprintk(VIDC_ERR, "%s - buf->handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = buf->buffer_type;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ if (inst->state != MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(&inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Rel scrtch buf fail:%pa, %d\n",
+ &buffer_info.align_device_addr,
+ buffer_info.buffer_size);
+ }
+ mutex_unlock(&inst->internalbufs.lock);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ change_inst_state(inst,
+ MSM_VIDC_CORE_INVALID);
+ msm_comm_kill_session(inst);
+ }
+ mutex_lock(&inst->internalbufs.lock);
+ }
+
+ /*If scratch buffers can be reused, do not free the buffers*/
+ if (sufficiency & buf->buffer_type)
+ continue;
+
+ list_del(&buf->list);
+ msm_comm_smem_free(inst, buf->handle);
+ kfree(buf);
+ }
+
+exit:
+ mutex_unlock(&inst->internalbufs.lock);
+ return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst->persistbufs.lock);
+ list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = buf->buffer_type;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ if (inst->state != MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Rel prst buf fail:%pa, %d\n",
+ &buffer_info.align_device_addr,
+ buffer_info.buffer_size);
+ }
+ mutex_unlock(&inst->persistbufs.lock);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+ msm_comm_kill_session(inst);
+ }
+ mutex_lock(&inst->persistbufs.lock);
+ }
+ list_del(&buf->list);
+ msm_comm_smem_free(inst, buf->handle);
+ kfree(buf);
+ }
+ mutex_unlock(&inst->persistbufs.lock);
+ return rc;
+}
+
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", inst);
+ return -EINVAL;
+ }
+
+ if (!inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR, "Not in proper state to set property\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
+ rc = call_hfi_op(hdev, session_set_property, (void *)inst->session,
+ ptype, pdata);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_comm_release_output_buffers(inst))
+ dprintk(VIDC_WARN, "Failed to release output buffers\n");
+
+ rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
+ if (rc)
+ goto error;
+ return rc;
+error:
+ msm_comm_release_output_buffers(inst);
+ return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_comm_release_scratch_buffers(inst, true))
+ dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
+
+ rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH);
+ if (rc)
+ goto error;
+
+ rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1);
+ if (rc)
+ goto error;
+
+ rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2);
+ if (rc)
+ goto error;
+
+ return rc;
+error:
+ msm_comm_release_scratch_buffers(inst, false);
+ return rc;
+}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST);
+ if (rc)
+ goto error;
+
+ rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1);
+ if (rc)
+ goto error;
+ return rc;
+error:
+ msm_comm_release_persist_buffers(inst);
+ return rc;
+}
+
+static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst)
+{
+ struct list_head *ptr, *next;
+ enum vidc_ports ports[] = {OUTPUT_PORT, CAPTURE_PORT};
+ int c = 0;
+
+ for (c = 0; c < ARRAY_SIZE(ports); ++c) {
+ enum vidc_ports port = ports[c];
+
+ dprintk(VIDC_DBG, "Flushing buffers of type %d in bad state\n",
+ port);
+ list_for_each_safe(ptr, next, &inst->bufq[port].
+ vb2_bufq.queued_list) {
+ struct vb2_buffer *vb = container_of(ptr,
+ struct vb2_buffer, queued_entry);
+
+ vb->v4l2_planes[0].bytesused = 0;
+ vb->v4l2_planes[0].data_offset = 0;
+
+ mutex_lock(&inst->bufq[port].lock);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[port].lock);
+ }
+ }
+
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+ return;
+}
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *binfo = NULL;
+
+ if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+ return;
+
+ /*
+ * dynamic buffer mode:- if flush is called during seek
+ * driver should not queue any new buffer it has been holding.
+ *
+ * Each dynamic o/p buffer can have one of following ref_count:
+ * ref_count : 0 - f/w has released reference and sent fbd back.
+ * The buffer has been returned back to client.
+ *
+ * ref_count : 1 - f/w is holding reference. f/w may have released
+ * fbd as read_only OR fbd is pending. f/w will
+ * release reference before sending flush_done.
+ *
+ * ref_count : 2 - f/w is holding reference, f/w has released fbd as
+ * read_only, which client has queued back to driver.
+ * driver holds this buffer and will queue back
+ * only when f/w releases the reference. During
+ * flush_done, f/w will release the reference but driver
+ * should not queue back the buffer to f/w.
+ * Flush all buffers with ref_count 2.
+ */
+ mutex_lock(&inst->registeredbufs.lock);
+ if (!list_empty(&inst->registeredbufs.list)) {
+ struct v4l2_event buf_event = {0};
+ u32 *ptr = NULL;
+
+ list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+ if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ atomic_read(&binfo->ref_count) == 2) {
+
+ atomic_dec(&binfo->ref_count);
+ buf_event.type =
+ V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+ ptr[2] = binfo->uvaddr[0];
+ ptr[3] = (u32) binfo->timestamp.tv_sec;
+ ptr[4] = (u32) binfo->timestamp.tv_usec;
+ ptr[5] = binfo->v4l2_index;
+ dprintk(VIDC_DBG,
+ "released buffer held in driver before issuing flush: %pa fd[0]: %d\n",
+ &binfo->device_addr[0], binfo->fd[0]);
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler,
+ &buf_event);
+ }
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+}
+
+void msm_comm_flush_pending_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *binfo = NULL;
+
+ if (!inst)
+ return;
+
+ if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+ return;
+
+ if (list_empty(&inst->pendingq.list) ||
+ list_empty(&inst->registeredbufs.list))
+ return;
+
+ /*
+ * Dynamic Buffer mode - Since pendingq is not empty
+ * no output buffers have been sent to firmware yet.
+ * Hence remove reference to all pendingq o/p buffers
+ * before flushing them.
+ */
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+ if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ dprintk(VIDC_DBG,
+ "%s: binfo = %p device_addr = %pa\n",
+ __func__, binfo, &binfo->device_addr[0]);
+ buf_ref_put(inst, binfo);
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+}
+
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
+{
+ int rc = 0;
+ bool ip_flush = false;
+ bool op_flush = false;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *temp;
+ struct mutex *lock;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
+
+ ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
+ op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
+
+ if (ip_flush && !op_flush) {
+ dprintk(VIDC_INFO, "Input only flush not supported\n");
+ return 0;
+ }
+
+ msm_comm_flush_dynamic_buffers(inst);
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core %p and inst %p are in bad state\n",
+ core, inst);
+ msm_comm_flush_in_invalid_state(inst);
+ return 0;
+ }
+
+ if (inst->in_reconfig && !ip_flush && op_flush) {
+ mutex_lock(&inst->pendingq.lock);
+ if (!list_empty(&inst->pendingq.list)) {
+ /*
+ * Execution can never reach here since port reconfig
+ * wont happen unless pendingq is emptied out
+ * (both pendingq and flush being secured with same
+ * lock). Printing a message here incase this breaks.
+ */
+ dprintk(VIDC_WARN,
+ "FLUSH BUG: Pending q not empty! It should be empty\n");
+ }
+ mutex_unlock(&inst->pendingq.lock);
+ rc = call_hfi_op(hdev, session_flush, inst->session,
+ HAL_FLUSH_OUTPUT);
+ if (!rc && msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY)
+ rc = call_hfi_op(hdev, session_flush, inst->session,
+ HAL_FLUSH_OUTPUT2);
+
+ } else {
+ msm_comm_flush_pending_dynamic_buffers(inst);
+ /*
+ * If flush is called after queueing buffers but before
+ * streamon driver should flush the pending queue
+ */
+ mutex_lock(&inst->pendingq.lock);
+ list_for_each_safe(ptr, next, &inst->pendingq.list) {
+ temp =
+ list_entry(ptr, struct vb2_buf_entry, list);
+ if (temp->vb->v4l2_buf.type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ lock = &inst->bufq[CAPTURE_PORT].lock;
+ else
+ lock = &inst->bufq[OUTPUT_PORT].lock;
+ temp->vb->v4l2_planes[0].bytesused = 0;
+ mutex_lock(lock);
+ vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(lock);
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ mutex_unlock(&inst->pendingq.lock);
+
+ /*Do not send flush in case of session_error */
+ if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID))
+ rc = call_hfi_op(hdev, session_flush, inst->session,
+ HAL_FLUSH_ALL);
+ }
+
+ return rc;
+}
+
+
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+ enum v4l2_mpeg_vidc_extradata index)
+{
+ int ret = 0;
+ switch (index) {
+ case V4L2_MPEG_VIDC_EXTRADATA_NONE:
+ ret = HAL_EXTRADATA_NONE;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION:
+ ret = HAL_EXTRADATA_MB_QUANTIZATION;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO:
+ ret = HAL_EXTRADATA_INTERLACE_VIDEO;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP:
+ ret = HAL_EXTRADATA_VC1_FRAMEDISP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP:
+ ret = HAL_EXTRADATA_VC1_SEQDISP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP:
+ ret = HAL_EXTRADATA_TIMESTAMP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING:
+ ret = HAL_EXTRADATA_S3D_FRAME_PACKING;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE:
+ ret = HAL_EXTRADATA_FRAME_RATE;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW:
+ ret = HAL_EXTRADATA_PANSCAN_WINDOW;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI:
+ ret = HAL_EXTRADATA_RECOVERY_POINT_SEI;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
+ ret = HAL_EXTRADATA_MULTISLICE_INFO;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
+ ret = HAL_EXTRADATA_NUM_CONCEALED_MB;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
+ ret = HAL_EXTRADATA_METADATA_FILLER;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
+ ret = HAL_EXTRADATA_ASPECT_RATIO;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
+ ret = HAL_EXTRADATA_INPUT_CROP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
+ ret = HAL_EXTRADATA_DIGITAL_ZOOM;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
+ ret = HAL_EXTRADATA_MPEG2_SEQDISP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA:
+ ret = HAL_EXTRADATA_STREAM_USERDATA;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP:
+ ret = HAL_EXTRADATA_FRAME_QP;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO:
+ ret = HAL_EXTRADATA_FRAME_BITS_INFO;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+ ret = HAL_EXTRADATA_LTR_INFO;
+ break;
+ case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+ ret = HAL_EXTRADATA_METADATA_MBI;
+ break;
+ default:
+ dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
+ break;
+ }
+ return ret;
+};
+
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+ enum v4l2_mpeg_vidc_video_mvc_layout index)
+{
+ int ret = 0;
+ switch (index) {
+ case V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL:
+ ret = HAL_BUFFER_LAYOUT_SEQ;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM:
+ ret = HAL_BUFFER_LAYOUT_TOP_BOTTOM;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+ enum hal_ssr_trigger_type type)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ if (!core || !core->device) {
+ dprintk(VIDC_WARN, "Invalid parameters: %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (core->state == VIDC_CORE_INIT_DONE)
+ rc = call_hfi_op(hdev, core_trigger_ssr,
+ hdev->hfi_device_data, type);
+ return rc;
+}
+
+static int msm_vidc_load_supported(struct msm_vidc_inst *inst)
+{
+ int num_mbs_per_sec = 0;
+ enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+ LOAD_CALC_IGNORE_THUMBNAIL_LOAD;
+
+ if (inst->state == MSM_VIDC_OPEN_DONE) {
+ num_mbs_per_sec = msm_comm_get_load(inst->core,
+ MSM_VIDC_DECODER, quirks);
+ num_mbs_per_sec += msm_comm_get_load(inst->core,
+ MSM_VIDC_ENCODER, quirks);
+ if (num_mbs_per_sec > inst->core->resources.max_load) {
+ dprintk(VIDC_ERR,
+ "H/W is overloaded. needed: %d max: %d\n",
+ num_mbs_per_sec,
+ inst->core->resources.max_load);
+ msm_vidc_print_running_insts(inst->core);
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+ u32 x_min, x_max, y_min, y_max;
+ u32 input_height, input_width, output_height, output_width;
+
+ input_height = inst->prop.height[OUTPUT_PORT];
+ input_width = inst->prop.width[OUTPUT_PORT];
+ output_height = inst->prop.height[CAPTURE_PORT];
+ output_width = inst->prop.width[CAPTURE_PORT];
+
+ if (!input_height || !input_width || !output_height || !output_width) {
+ dprintk(VIDC_ERR,
+ "Invalid : Input height = %d width = %d"
+ " output height = %d width = %d\n",
+ input_height, input_width, output_height,
+ output_width);
+ return -ENOTSUPP;
+ }
+
+ if (!inst->capability.scale_x.min ||
+ !inst->capability.scale_x.max ||
+ !inst->capability.scale_y.min ||
+ !inst->capability.scale_y.max) {
+
+ if (input_width * input_height !=
+ output_width * output_height) {
+ dprintk(VIDC_ERR,
+ "%s: scaling is not supported (%dx%d != %dx%d)\n",
+ __func__, input_width, input_height,
+ output_width, output_height);
+ return -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG, "%s: supported WxH = %dx%d\n",
+ __func__, input_width, input_height);
+ return 0;
+ }
+ }
+
+ x_min = (1<<16)/inst->capability.scale_x.min;
+ y_min = (1<<16)/inst->capability.scale_y.min;
+ x_max = inst->capability.scale_x.max >> 16;
+ y_max = inst->capability.scale_y.max >> 16;
+
+ if (input_height > output_height) {
+ if (input_height/output_height > x_min) {
+ dprintk(VIDC_ERR,
+ "Unsupported height downscale ratio %d vs %d\n",
+ input_height/output_height, x_min);
+ return -ENOTSUPP;
+ }
+ } else {
+ if (input_height/output_height > x_max) {
+ dprintk(VIDC_ERR,
+ "Unsupported height upscale ratio %d vs %d\n",
+ input_height/output_height, x_max);
+ return -ENOTSUPP;
+ }
+ }
+ if (input_width > output_width) {
+ if (input_width/output_width > y_min) {
+ dprintk(VIDC_ERR,
+ "Unsupported width downscale ratio %d vs %d\n",
+ input_width/output_width, y_min);
+ return -ENOTSUPP;
+ }
+ } else {
+ if (input_width/output_width > y_max) {
+ dprintk(VIDC_ERR,
+ "Unsupported width upscale ratio %d vs %d\n",
+ input_width/output_width, y_max);
+ return -ENOTSUPP;
+ }
+ }
+ return 0;
+}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core_capability *capability;
+ int rc = 0;
+ struct hfi_device *hdev;
+ struct msm_vidc_core *core;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+ capability = &inst->capability;
+ hdev = inst->core->device;
+ core = inst->core;
+ rc = msm_vidc_load_supported(inst);
+ if (rc) {
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+ dprintk(VIDC_WARN,
+ "%s: Hardware is overloaded\n", __func__);
+ return rc;
+ }
+
+ if (!is_thermal_permissible(core)) {
+ dprintk(VIDC_WARN,
+ "Thermal level critical, stop all active sessions!\n");
+ return -ENOTSUPP;
+ }
+
+ if (!rc && inst->capability.capability_set) {
+ if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+ inst->prop.height[CAPTURE_PORT] <
+ capability->height.min) {
+ dprintk(VIDC_ERR,
+ "Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ capability->width.min,
+ capability->height.min);
+ rc = -ENOTSUPP;
+ }
+ if (!rc && inst->prop.width[CAPTURE_PORT] >
+ capability->width.max) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %u supported max width = %u",
+ inst->prop.width[CAPTURE_PORT],
+ capability->width.max);
+ rc = -ENOTSUPP;
+ }
+
+ if (!rc && inst->prop.height[CAPTURE_PORT]
+ * inst->prop.width[CAPTURE_PORT] >
+ capability->width.max * capability->height.max) {
+ dprintk(VIDC_ERR,
+ "Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n",
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ capability->width.max, capability->height.max);
+ rc = -ENOTSUPP;
+ }
+ }
+ if (rc) {
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+ dprintk(VIDC_ERR,
+ "%s: Resolution unsupported\n", __func__);
+ }
+ return rc;
+}
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+ enum command_response cmd = SESSION_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+
+ dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+ return;
+ }
+
+ response.session_id = inst;
+ response.status = VIDC_ERR_FAIL;
+ handle_session_error(cmd, (void *)&response);
+}
+
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ enum command_response cmd = SYS_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+ return;
+ }
+ core = inst->core;
+ response.device_id = (u32) core->id;
+ handle_sys_error(cmd, (void *) &response);
+
+}
+
+int msm_comm_kill_session(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+ return -EINVAL;
+ } else if (!inst->session) {
+ /* There's no hfi session to kill */
+ return 0;
+ }
+
+ /*
+ * We're internally forcibly killing the session, if fw is aware of
+ * the session send session_abort to firmware to clean up and release
+ * the session, else just kill the session inside the driver.
+ */
+ if ((inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_CLOSE_DONE) ||
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_session_abort(inst);
+ if (rc == -EBUSY) {
+ msm_comm_generate_sys_error(inst);
+ return 0;
+ } else if (rc)
+ return rc;
+
+ change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+ } else {
+ dprintk(VIDC_WARN,
+ "Inactive session %p, triggering an internal session error\n",
+ inst);
+ msm_comm_generate_session_error(inst);
+
+ }
+
+ return rc;
+}
+
+static inline int power_on_for_smem(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid inst handle\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ rc = call_hfi_op(hdev, power_enable, hdev->hfi_device_data);
+ if (rc)
+ dprintk(VIDC_ERR, "%s: failed to power on fw\n", __func__);
+ return rc;
+}
+
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ struct msm_smem *m = NULL;
+
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ mutex_lock(&inst->core->lock);
+ if (power_on_for_smem(inst))
+ goto err_power_on;
+
+ m = msm_smem_alloc(inst->mem_client, size, align,
+ flags, buffer_type, map_kernel);
+err_power_on:
+ mutex_unlock(&inst->core->lock);
+ return m;
+}
+
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
+{
+ if (!inst || !inst->core || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return;
+ }
+ mutex_lock(&inst->core->lock);
+ if (power_on_for_smem(inst))
+ goto err_power_on;
+
+ msm_smem_free(inst->mem_client, mem);
+err_power_on:
+ mutex_unlock(&inst->core->lock);
+}
+
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops)
+{
+ if (!inst || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return -EINVAL;
+ }
+ return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+}
+
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type)
+{
+ struct msm_smem *m = NULL;
+
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ mutex_lock(&inst->core->lock);
+ if (power_on_for_smem(inst))
+ goto err_power_on;
+
+ m = msm_smem_user_to_kernel(inst->mem_client,
+ fd, offset, buffer_type);
+err_power_on:
+ mutex_unlock(&inst->core->lock);
+ return m;
+}
+
+void msm_vidc_fw_unload_handler(struct work_struct *work)
+{
+ struct msm_vidc_core *core = NULL;
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ core = container_of(work, struct msm_vidc_core, fw_unload_work.work);
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+ __func__);
+ return;
+ }
+
+ hdev = core->device;
+
+ mutex_lock(&core->lock);
+ if (list_empty(&core->instances) &&
+ core->state != VIDC_CORE_UNINIT) {
+ if (core->state > VIDC_CORE_INIT) {
+ dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
+ 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);
+ return;
+ }
+ }
+
+ core->state = VIDC_CORE_UNINIT;
+
+ call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
+ dprintk(VIDC_DBG, "Firmware unloaded\n");
+ }
+ mutex_unlock(&core->lock);
+}
+
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type, int fourcc)
+{
+ struct hal_uncompressed_format_select hal_fmt = {0};
+ int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+ hal_fmt.buffer_type = buffer_type;
+
+ switch (fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ dprintk(VIDC_DBG, "set color format: nv12\n");
+ hal_fmt.format = HAL_COLOR_FORMAT_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ dprintk(VIDC_DBG, "set color format: nv21\n");
+ hal_fmt.format = HAL_COLOR_FORMAT_NV21;
+ break;
+ case V4L2_PIX_FMT_NV12_UBWC:
+ dprintk(VIDC_DBG, "set color format: nv12_ubwc\n");
+ hal_fmt.format = HAL_COLOR_FORMAT_NV12_UBWC;
+ break;
+ case V4L2_PIX_FMT_NV12_TP10_UBWC:
+ dprintk(VIDC_DBG, "set color format: 10bit nv12_ubwc\n");
+ hal_fmt.format = HAL_COLOR_FORMAT_NV12_TP10_UBWC;
+ break;
+ default:
+ dprintk(VIDC_ERR, "%s default\n", __func__);
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to set input color format\n");
+
+exit:
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
new file mode 100644
index 000000000000..9a1bf957319f
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+ struct list_head list;
+ struct vb2_buffer *vb;
+};
+
+enum load_calc_quirks {
+ LOAD_CALC_NO_QUIRKS = 0,
+ LOAD_CALC_IGNORE_TURBO_LOAD = 1 << 0,
+ LOAD_CALC_IGNORE_THUMBNAIL_LOAD = 1 << 1,
+};
+
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct buf_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata);
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, union hal_get_property *hprop);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct vb2_buffer *vb);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
+int msm_comm_scale_clocks(struct msm_vidc_core *core);
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core, int num_mbs_per_sec);
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+ bool check_for_reuse);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
+int msm_comm_suspend(int core_id);
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+ enum v4l2_mpeg_vidc_extradata index);
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+ enum v4l2_mpeg_vidc_video_mvc_layout index);
+struct hal_buffer_requirements *get_buff_req_buffer(
+ struct msm_vidc_inst *inst, u32 buffer_type);
+#define IS_PRIV_CTRL(idx) (\
+ (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
+ V4L2_CTRL_DRIVER_PRIV(idx))
+void msm_comm_session_clean(struct msm_vidc_inst *inst);
+int msm_comm_kill_session(struct msm_vidc_inst *inst);
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops);
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type);
+enum hal_video_codec get_hal_codec_type(int fourcc);
+int msm_comm_load_fw(struct msm_vidc_core *core);
+int msm_comm_check_core_init(struct msm_vidc_core *core);
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+ enum load_calc_quirks quirks);
+int msm_comm_get_load(struct msm_vidc_core *core,
+ enum session_type type, enum load_calc_quirks quirks);
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type, int fourcc);
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
new file mode 100644
index 000000000000..3e9ef063d0a4
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
@@ -0,0 +1,617 @@
+/* Copyright (c) 2014 - 2015, 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 "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_VALID_DCVS_SESSION(__cur_mbpf, __min_mbpf) \
+ ((__cur_mbpf) >= (__min_mbpf))
+
+static int msm_dcvs_check_supported(struct msm_vidc_inst *inst);
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst);
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd);
+
+static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+ int height, width;
+
+ height = inst->prop.height[CAPTURE_PORT];
+ width = inst->prop.width[CAPTURE_PORT];
+ return NUM_MBS_PER_FRAME(height, width);
+}
+
+static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core)
+{
+ int active_instances = 0;
+ struct msm_vidc_inst *inst = NULL;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, core);
+ return -EINVAL;
+ }
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->state >= MSM_VIDC_START_DONE &&
+ inst->state < MSM_VIDC_STOP_DONE)
+ active_instances++;
+ }
+ mutex_unlock(&core->lock);
+ return active_instances;
+}
+
+static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+
+ if (inst->session_type == MSM_VIDC_ENCODER && msm_vidc_enc_dcvs_mode) {
+ rc = msm_dcvs_check_supported(inst);
+ if (!rc) {
+ inst->dcvs_mode = true;
+ dprintk(VIDC_DBG,
+ "%s: session DCVS supported, enc_dcvs_mode = %d\n",
+ __func__, inst->dcvs_mode);
+ } else {
+ inst->dcvs_mode = false;
+ dprintk(VIDC_DBG,
+ "%s: session DCVS not supported, enc_dcvs_mode = %d\n",
+ __func__, inst->dcvs_mode);
+ }
+
+ if (inst->dcvs_mode) {
+ rc = msm_dcvs_enc_scale_clocks(inst);
+ if (rc) {
+ dprintk(VIDC_DBG,
+ "ENC_DCVS: error while scaling clocks\n");
+ }
+ }
+ }
+}
+
+static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+
+ if (inst->session_type != MSM_VIDC_DECODER)
+ return;
+
+ rc = msm_dcvs_check_supported(inst);
+ if (!rc) {
+ inst->dcvs_mode = true;
+ dprintk(VIDC_DBG,
+ "%s: session DCVS supported, decode_dcvs_mode = %d\n",
+ __func__, inst->dcvs_mode);
+ } else {
+ inst->dcvs_mode = false;
+ dprintk(VIDC_DBG,
+ "%s: session DCVS not supported, decode_dcvs_mode = %d\n",
+ __func__, inst->dcvs_mode);
+ }
+
+ if (msm_vidc_dec_dcvs_mode && inst->dcvs_mode) {
+ msm_dcvs_monitor_buffer(inst);
+ rc = msm_dcvs_dec_scale_clocks(inst, false);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to scale clocks in DCVS: %d\n",
+ __func__, rc);
+ }
+ }
+}
+
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, inst);
+ return;
+ }
+
+ if (is_etb)
+ msm_dcvs_enc_check_and_scale_clocks(inst);
+ else
+ msm_dcvs_dec_check_and_scale_clocks(inst);
+}
+
+static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
+{
+ int fw_out_qsize = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_STOP_DONE)
+ fw_out_qsize = inst->count.ftb - inst->count.fbd;
+
+ return fw_out_qsize;
+}
+
+static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
+{
+ dprintk(VIDC_DBG,
+ "DCVS: Load_Low %d, Load High %d\n",
+ dcvs->load_low,
+ dcvs->load_high);
+
+ dprintk(VIDC_DBG,
+ "DCVS: ThrDispBufLow %d, ThrDispBufHigh %d\n",
+ dcvs->threshold_disp_buf_low,
+ dcvs->threshold_disp_buf_high);
+
+ dprintk(VIDC_DBG,
+ "DCVS: min_threshold %d, max_threshold %d\n",
+ dcvs->min_threshold, dcvs->max_threshold);
+}
+
+void msm_dcvs_init_load(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ struct hal_buffer_requirements *output_buf_req;
+ struct dcvs_stats *dcvs;
+
+ dprintk(VIDC_DBG, "Init DCVS Load\n");
+
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, inst);
+ return;
+ }
+
+ core = inst->core;
+ dcvs = &inst->dcvs;
+
+ dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+
+ if (dcvs->load >= DCVS_NOMINAL_LOAD) {
+ dcvs->load_low = DCVS_NOMINAL_LOAD;
+ dcvs->load_high = core->resources.max_load;
+ }
+
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ goto print_stats;
+
+ output_buf_req = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+
+ if (!output_buf_req) {
+ dprintk(VIDC_ERR,
+ "%s: No buffer requirement for buffer type %x\n",
+ __func__, HAL_BUFFER_OUTPUT);
+ return;
+ }
+
+ dcvs->transition_turbo = false;
+
+ /* calculating the min and max threshold */
+ if (output_buf_req->buffer_count_actual) {
+ dcvs->min_threshold = DCVS_MIN_DISPLAY_BUFF;
+ dcvs->max_threshold = output_buf_req->buffer_count_actual;
+ if (dcvs->max_threshold <= dcvs->min_threshold)
+ dcvs->max_threshold =
+ dcvs->min_threshold + DCVS_BUFFER_SAFEGUARD;
+ dcvs->threshold_disp_buf_low = dcvs->min_threshold;
+ dcvs->threshold_disp_buf_high = dcvs->max_threshold;
+ }
+
+print_stats:
+ msm_dcvs_print_dcvs_stats(dcvs);
+}
+
+void msm_dcvs_init(struct msm_vidc_inst *inst)
+{
+ dprintk(VIDC_DBG, "Init DCVS Struct\n");
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, inst);
+ return;
+ }
+
+ inst->dcvs = (struct dcvs_stats){ {0} };
+ inst->dcvs.threshold_disp_buf_high = DCVS_NOMINAL_THRESHOLD;
+ inst->dcvs.threshold_disp_buf_low = DCVS_TURBO_THRESHOLD;
+}
+
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst)
+{
+ int new_ftb, i, prev_buf_count;
+ int fw_pending_bufs, total_output_buf, buffers_outside_fw;
+ struct dcvs_stats *dcvs;
+ struct hal_buffer_requirements *output_buf_req;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, inst);
+ return;
+ }
+ dcvs = &inst->dcvs;
+
+ mutex_lock(&inst->lock);
+ output_buf_req = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+ if (!output_buf_req) {
+ dprintk(VIDC_ERR, "%s : Get output buffer req failed %p\n",
+ __func__, inst);
+ mutex_unlock(&inst->lock);
+ return;
+ }
+ total_output_buf = output_buf_req->buffer_count_actual;
+ fw_pending_bufs = get_pending_bufs_fw(inst) + 1;
+ mutex_unlock(&inst->lock);
+
+ buffers_outside_fw = total_output_buf - fw_pending_bufs;
+ dcvs->num_ftb[dcvs->ftb_index] = buffers_outside_fw;
+ dcvs->ftb_index = (dcvs->ftb_index + 1) % DCVS_FTB_WINDOW;
+
+ if (dcvs->ftb_counter < DCVS_FTB_WINDOW)
+ dcvs->ftb_counter++;
+
+ dprintk(VIDC_PROF,
+ "DCVS: ftb_counter %d\n", dcvs->ftb_counter);
+
+ if (dcvs->ftb_counter == DCVS_FTB_WINDOW) {
+ new_ftb = 0;
+ for (i = 0; i < dcvs->ftb_counter; i++) {
+ if (dcvs->num_ftb[i] > new_ftb)
+ new_ftb = dcvs->num_ftb[i];
+ }
+ dcvs->threshold_disp_buf_high = new_ftb;
+ if (dcvs->threshold_disp_buf_high <=
+ dcvs->threshold_disp_buf_low) {
+ dcvs->threshold_disp_buf_high =
+ dcvs->threshold_disp_buf_low +
+ DCVS_BUFFER_SAFEGUARD;
+ }
+ dcvs->threshold_disp_buf_high =
+ clamp(dcvs->threshold_disp_buf_high,
+ dcvs->min_threshold,
+ dcvs->max_threshold);
+ }
+ if (dcvs->ftb_counter == DCVS_FTB_WINDOW &&
+ dcvs->load == dcvs->load_low) {
+ prev_buf_count =
+ dcvs->num_ftb[((dcvs->ftb_index - 2 +
+ DCVS_FTB_WINDOW) % DCVS_FTB_WINDOW)];
+ if (prev_buf_count == DCVS_MIN_DISPLAY_BUFF &&
+ buffers_outside_fw == DCVS_MIN_DISPLAY_BUFF) {
+ dcvs->transition_turbo = true;
+ } else if (buffers_outside_fw > DCVS_MIN_DISPLAY_BUFF &&
+ (buffers_outside_fw -
+ (prev_buf_count - buffers_outside_fw))
+ < DCVS_MIN_DISPLAY_BUFF){
+ dcvs->transition_turbo = true;
+ }
+ }
+ dprintk(VIDC_PROF,
+ "DCVS: total_output_buf %d buffers_outside_fw %d load %d transition_turbo %d\n",
+ total_output_buf, buffers_outside_fw, dcvs->load_low,
+ dcvs->transition_turbo);
+}
+
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
+{
+ int rc = 0, fw_pending_bufs = 0, total_input_buf = 0;
+ struct msm_vidc_core *core;
+ struct dcvs_stats *dcvs;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ dcvs = &inst->dcvs;
+
+ mutex_lock(&inst->lock);
+ total_input_buf = inst->buff_req.buffer[0].buffer_count_actual;
+ fw_pending_bufs = (inst->count.etb - inst->count.ebd);
+ mutex_unlock(&inst->lock);
+
+ dprintk(VIDC_PROF,
+ "DCVS: total_input_buf %d, fw_pending_bufs %d\n",
+ total_input_buf, fw_pending_bufs);
+
+ if (dcvs->etb_counter < total_input_buf) {
+ dcvs->etb_counter++;
+ if (dcvs->etb_counter != total_input_buf)
+ return rc;
+ }
+
+ dprintk(VIDC_PROF,
+ "DCVS: total_input_buf %d, fw_pending_bufs %d etb_counter %d dcvs->load %d\n",
+ total_input_buf, fw_pending_bufs,
+ dcvs->etb_counter, dcvs->load);
+
+ if (fw_pending_bufs <= DCVS_ENC_LOW_THR &&
+ dcvs->load > dcvs->load_low) {
+ dcvs->load = dcvs->load_low;
+ dcvs->prev_freq_lowered = true;
+ } else {
+ dcvs->prev_freq_lowered = false;
+ }
+
+ if (fw_pending_bufs >= DCVS_ENC_HIGH_THR &&
+ dcvs->load <= dcvs->load_low) {
+ dcvs->load = dcvs->load_high;
+ dcvs->prev_freq_increased = true;
+ } else {
+ dcvs->prev_freq_increased = false;
+ }
+
+ if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+ dprintk(VIDC_PROF,
+ "DCVS: (Scaling Clock %s) etb clock set = %d total_input_buf = %d fw_pending_bufs %d\n",
+ dcvs->prev_freq_lowered ? "Lower" : "Higher",
+ dcvs->load, total_input_buf, fw_pending_bufs);
+
+ rc = msm_comm_scale_clocks_load(core, dcvs->load);
+ if (rc) {
+ dprintk(VIDC_PROF,
+ "Failed to set clock rate in FBD: %d\n", rc);
+ }
+ } else {
+ dprintk(VIDC_PROF,
+ "DCVS: etb clock load_old = %d total_input_buf = %d fw_pending_bufs %d\n",
+ dcvs->load, total_input_buf, fw_pending_bufs);
+ }
+
+ return rc;
+}
+
+
+/*
+ * In DCVS scale_clocks will be done both in qbuf and FBD
+ * 1 indicates call made from fbd that lowers clock
+ * 0 indicates call made from qbuf that increases clock
+ * based on DCVS algorithm
+ */
+
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd)
+{
+ int rc = 0;
+ int fw_pending_bufs = 0;
+ int total_output_buf = 0;
+ int buffers_outside_fw = 0;
+ struct msm_vidc_core *core;
+ struct hal_buffer_requirements *output_buf_req;
+ struct dcvs_stats *dcvs;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ core = inst->core;
+ dcvs = &inst->dcvs;
+ mutex_lock(&inst->lock);
+ fw_pending_bufs = get_pending_bufs_fw(inst) +
+ (fbd ? 0 : 1);
+
+ output_buf_req = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+ mutex_unlock(&inst->lock);
+ if (!output_buf_req) {
+ dprintk(VIDC_ERR,
+ "%s: No buffer requirement for buffer type %x\n",
+ __func__, HAL_BUFFER_OUTPUT);
+ return -EINVAL;
+ }
+
+ /* Total number of output buffers */
+ total_output_buf = output_buf_req->buffer_count_actual;
+
+ /* Buffers outside FW are with display */
+ buffers_outside_fw = total_output_buf - fw_pending_bufs;
+
+ if (buffers_outside_fw >= dcvs->threshold_disp_buf_high &&
+ !dcvs->prev_freq_increased &&
+ dcvs->load > dcvs->load_low) {
+ dcvs->load = dcvs->load_low;
+ dcvs->prev_freq_lowered = true;
+ dcvs->prev_freq_increased = false;
+ } else if (dcvs->transition_turbo && dcvs->load == dcvs->load_low) {
+ dcvs->load = dcvs->load_high;
+ dcvs->prev_freq_increased = true;
+ dcvs->prev_freq_lowered = false;
+ dcvs->transition_turbo = false;
+ } else {
+ dcvs->prev_freq_increased = false;
+ dcvs->prev_freq_lowered = false;
+ }
+
+ if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+ dprintk(VIDC_PROF,
+ "DCVS: clock set = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+ dcvs->load, total_output_buf, buffers_outside_fw,
+ dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+
+ rc = msm_comm_scale_clocks_load(core, dcvs->load);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set clock rate in FBD: %d\n", rc);
+ }
+ } else {
+ dprintk(VIDC_PROF,
+ "DCVS: clock old = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+ dcvs->load, total_output_buf, buffers_outside_fw,
+ dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+ }
+ return rc;
+}
+
+bool msm_dcvs_enc_check(struct msm_vidc_inst *inst)
+{
+ int num_mbs_per_frame = 0;
+ bool dcvs_check_passed = false, is_codec_supported = false;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+ return dcvs_check_passed;
+ }
+
+ is_codec_supported =
+ (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264) ||
+ (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264_NO_SC);
+
+ num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+ if (msm_vidc_enc_dcvs_mode && is_codec_supported &&
+ inst->dcvs.is_power_save_mode &&
+ IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+ DCVS_MIN_SUPPORTED_MBPERFRAME)) {
+ dcvs_check_passed = true;
+ }
+ return dcvs_check_passed;
+}
+
+static int msm_dcvs_check_supported(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int num_mbs_per_frame = 0;
+ int instance_count = 0;
+ struct msm_vidc_inst *temp = NULL;
+ struct msm_vidc_core *core;
+ struct hal_buffer_requirements *output_buf_req;
+ struct dcvs_stats *dcvs;
+ bool is_codec_supported = false;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ dcvs = &inst->dcvs;
+ instance_count = msm_dcvs_count_active_instances(core);
+
+ if (instance_count == 1 && inst->session_type == MSM_VIDC_DECODER) {
+ num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+ output_buf_req = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
+
+ is_codec_supported =
+ (inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264) ||
+ (inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_HEVC) ||
+ (inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_VP8) ||
+ (inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264_NO_SC);
+ if (!is_codec_supported ||
+ !IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+ DCVS_MIN_SUPPORTED_MBPERFRAME))
+ return -ENOTSUPP;
+
+ if (!output_buf_req) {
+ dprintk(VIDC_ERR,
+ "%s: No buffer requirement for buffer type %x\n",
+ __func__, HAL_BUFFER_OUTPUT);
+ return -EINVAL;
+ }
+ } else if (instance_count == 1 &&
+ inst->session_type == MSM_VIDC_ENCODER) {
+ if (!msm_dcvs_enc_check(inst) ||
+ !inst->dcvs.is_additional_buff_added)
+ return -ENOTSUPP;
+ } else {
+ rc = -ENOTSUPP;
+ /*
+ * For multiple instance use case with 4K, clocks will be scaled
+ * as per load in streamon, but the clocks may be scaled
+ * down as DCVS is running for first playback instance
+ * Rescaling the core clock for multiple instance use case
+ */
+ if (!dcvs->is_clock_scaled) {
+ if (!msm_comm_scale_clocks(core)) {
+ dcvs->is_clock_scaled = true;
+ dprintk(VIDC_DBG,
+ "%s: Scaled clocks = %d\n",
+ __func__, dcvs->is_clock_scaled);
+ } else {
+ dprintk(VIDC_DBG,
+ "%s: Failed to Scale clocks. Perf might be impacted\n",
+ __func__);
+ }
+ }
+ /*
+ * For multiple instance use case turn OFF DCVS algorithm
+ * immediately
+ */
+ if (instance_count > 1) {
+ mutex_lock(&core->lock);
+ list_for_each_entry(temp, &core->instances, list)
+ temp->dcvs_mode = false;
+ mutex_unlock(&core->lock);
+ }
+ }
+ return rc;
+}
+
+int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst,
+ bool is_input_buff)
+{
+ int extra_buffer = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (msm_dcvs_enc_check(inst)) {
+ if (is_input_buff && !inst->dcvs.is_input_buff_added)
+ extra_buffer = DCVS_ENC_EXTRA_INPUT_BUFFERS;
+ else if (!is_input_buff &&
+ !inst->dcvs.is_output_buff_added)
+ extra_buffer = DCVS_ENC_EXTRA_OUTPUT_BUFFERS;
+ }
+ }
+ return extra_buffer;
+}
+
+void msm_dcvs_set_buff_req_handled(struct msm_vidc_inst *inst,
+ bool is_input_buff)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+ return;
+ }
+
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ if (msm_dcvs_enc_check(inst)) {
+ if (is_input_buff && !inst->dcvs.is_input_buff_added)
+ inst->dcvs.is_input_buff_added = true;
+ else if (!is_input_buff &&
+ !inst->dcvs.is_output_buff_added)
+ inst->dcvs.is_output_buff_added = true;
+
+ if (inst->dcvs.is_input_buff_added &&
+ inst->dcvs.is_output_buff_added) {
+ inst->dcvs.is_additional_buff_added = true;
+ dprintk(VIDC_PROF,
+ "ENC_DCVS: additional i/p o/p buffer added");
+ }
+ }
+ }
+}
+
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+ bool is_power_save_mode)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+ return;
+ }
+
+ inst->dcvs.is_power_save_mode = is_power_save_mode;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h
new file mode 100644
index 000000000000..b239c6084314
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2014, 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_DCVS_H_
+#define _MSM_VIDC_DCVS_H_
+#include "msm_vidc_internal.h"
+
+/* Minimum number of display buffers */
+#define DCVS_MIN_DISPLAY_BUFF 4
+/* Low threshold for encoder dcvs */
+#define DCVS_ENC_LOW_THR 4
+/* High threshold for encoder dcvs */
+#define DCVS_ENC_HIGH_THR 9
+/* extra i/p buffers in case of encoder dcvs */
+#define DCVS_ENC_EXTRA_INPUT_BUFFERS 2
+/* extra o/p buffers in case of encoder dcvs */
+#define DCVS_ENC_EXTRA_OUTPUT_BUFFERS 2
+/* Default threshold to reduce the core frequency */
+#define DCVS_NOMINAL_THRESHOLD 8
+/* Default threshold to increase the core frequency */
+#define DCVS_TURBO_THRESHOLD 4
+/* Instance max load above which DCVS kicks in */
+#define DCVS_NOMINAL_LOAD NUM_MBS_PER_SEC(1088, 1920, 60)
+/* Considering one safeguard buffer */
+#define DCVS_BUFFER_SAFEGUARD 1
+/* Supported DCVS MBs per frame */
+#define DCVS_MIN_SUPPORTED_MBPERFRAME NUM_MBS_PER_FRAME(2160, 3840)
+
+void msm_dcvs_init(struct msm_vidc_inst *inst);
+void msm_dcvs_init_load(struct msm_vidc_inst *inst);
+bool msm_dcvs_enc_check(struct msm_vidc_inst *inst);
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst);
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb);
+int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst,
+ bool is_input_buff);
+void msm_dcvs_set_buff_req_handled(struct msm_vidc_inst *inst,
+ bool is_input_buff);
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+ bool is_power_save_mode);
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
new file mode 100644
index 000000000000..c7015d85f6fd
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+
+#define CREATE_TRACE_POINTS
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
+int msm_vidc_fw_debug = 0x18;
+int msm_vidc_fw_debug_mode = 1;
+int msm_vidc_fw_low_power_mode = 1;
+int msm_vidc_hw_rsp_timeout = 1000;
+int msm_vidc_fw_coverage = 0;
+int msm_vidc_vpe_csc_601_to_709 = 0;
+int msm_vidc_dec_dcvs_mode = 1;
+int msm_vidc_enc_dcvs_mode = 1;
+int msm_vidc_sys_idle_indicator = 0;
+int msm_vidc_firmware_unload_delay = 15000;
+int msm_vidc_thermal_mitigation_disabled = 0;
+
+#define MAX_DBG_BUF_SIZE 4096
+
+struct debug_buffer {
+ char ptr[MAX_DBG_BUF_SIZE];
+ char *curr;
+ u32 filled_size;
+};
+
+static struct debug_buffer dbg_buf;
+
+#define INIT_DBG_BUF(__buf) ({ \
+ __buf.curr = __buf.ptr;\
+ __buf.filled_size = 0; \
+})
+
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+ atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
+static int core_info_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...)
+{
+ va_list args;
+ u32 size;
+ va_start(args, fmt);
+ size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args);
+ va_end(args);
+ buffer->curr += size;
+ buffer->filled_size += size;
+ return size;
+}
+
+static ssize_t core_info_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_vidc_core *core = file->private_data;
+ struct hfi_device *hdev;
+ int i = 0;
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+ return 0;
+ }
+ hdev = core->device;
+ INIT_DBG_BUF(dbg_buf);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "CORE %d: %p\n", core->id, core);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "state: %d\n", core->state);
+ write_str(&dbg_buf, "base addr: %#x\n",
+ call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data,
+ FW_BASE_ADDRESS));
+ write_str(&dbg_buf, "register_base: %#x\n",
+ call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data,
+ FW_REGISTER_BASE));
+ write_str(&dbg_buf, "register_size: %u\n",
+ call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data,
+ FW_REGISTER_SIZE));
+ write_str(&dbg_buf, "irq: %u\n",
+ call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data,
+ FW_IRQ));
+ for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
+ write_str(&dbg_buf, "completions[%d]: %s\n", i,
+ completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
+ "pending" : "done");
+ }
+ return simple_read_from_buffer(buf, count, ppos,
+ dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations core_info_fops = {
+ .open = core_info_open,
+ .read = core_info_read,
+};
+
+static int trigger_ssr_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos) {
+ u32 ssr_trigger_val;
+ int rc;
+ struct msm_vidc_core *core = filp->private_data;
+ rc = sscanf(buf, "%d", &ssr_trigger_val);
+ if (rc < 0) {
+ dprintk(VIDC_WARN, "returning error err %d\n", rc);
+ rc = -EINVAL;
+ } else {
+ msm_vidc_trigger_ssr(core, ssr_trigger_val);
+ rc = count;
+ }
+ return rc;
+}
+
+static const struct file_operations ssr_fops = {
+ .open = trigger_ssr_open,
+ .write = trigger_ssr_write,
+};
+
+struct dentry *msm_vidc_debugfs_init_drv(void)
+{
+ bool ok = false;
+ struct dentry *dir = debugfs_create_dir("msm_vidc", NULL);
+ if (IS_ERR_OR_NULL(dir)) {
+ dir = NULL;
+ goto failed_create_dir;
+ }
+
+#define __debugfs_create(__type, __name, __value) ({ \
+ struct dentry *f = debugfs_create_##__type(__name, S_IRUGO | S_IWUSR, \
+ dir, __value); \
+ if (IS_ERR_OR_NULL(f)) { \
+ dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n", \
+ dir, __name); \
+ f = NULL; \
+ } \
+ f; \
+})
+
+ ok =
+ __debugfs_create(x32, "debug_level", &msm_vidc_debug) &&
+ __debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
+ __debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
+ __debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
+ __debugfs_create(bool, "dcvs_dec_mode", &msm_vidc_dec_dcvs_mode) &&
+ __debugfs_create(bool, "dcvs_enc_mode", &msm_vidc_enc_dcvs_mode) &&
+ __debugfs_create(u32, "fw_low_power_mode",
+ &msm_vidc_fw_low_power_mode) &&
+ __debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
+ __debugfs_create(u32, "hw_rsp_timeout", &msm_vidc_hw_rsp_timeout) &&
+ __debugfs_create(bool, "enable_vpe_csc_601_709",
+ &msm_vidc_vpe_csc_601_to_709) &&
+ __debugfs_create(bool, "sys_idle_indicator",
+ &msm_vidc_sys_idle_indicator) &&
+ __debugfs_create(u32, "firmware_unload_delay",
+ &msm_vidc_firmware_unload_delay) &&
+ __debugfs_create(bool, "disable_thermal_mitigation",
+ &msm_vidc_thermal_mitigation_disabled);
+
+#undef __debugfs_create
+
+ if (!ok)
+ goto failed_create_dir;
+
+ return dir;
+
+failed_create_dir:
+ if (dir)
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
+
+ return NULL;
+}
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+ struct dentry *parent)
+{
+ struct dentry *dir = NULL;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+ if (!core) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+ goto failed_create_dir;
+ }
+
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+ dir = debugfs_create_dir(debugfs_name, parent);
+ if (!dir) {
+ dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_file("trigger_ssr", S_IWUSR,
+ dir, core, &ssr_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+failed_create_dir:
+ return dir;
+}
+
+static int inst_info_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int publish_unreleased_reference(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *temp = NULL;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ write_str(&dbg_buf, "Pending buffer references:\n");
+
+ mutex_lock(&inst->registeredbufs.lock);
+ list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+ if (temp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ !temp->inactive && atomic_read(&temp->ref_count)) {
+ write_str(&dbg_buf,
+ "\tpending buffer: %#lx fd[0] = %d ref_count = %d held by: %s\n",
+ temp->device_addr[0],
+ temp->fd[0],
+ atomic_read(&temp->ref_count),
+ DYNAMIC_BUF_OWNER(temp));
+ }
+ }
+ mutex_unlock(&inst->registeredbufs.lock);
+ }
+ return 0;
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_vidc_inst *inst = file->private_data;
+ int i, j;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", inst);
+ return 0;
+ }
+ INIT_DBG_BUF(dbg_buf);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "INSTANCE: %p (%s)\n", inst,
+ inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "core: %p\n", inst->core);
+ write_str(&dbg_buf, "height: %d\n", inst->prop.height[CAPTURE_PORT]);
+ write_str(&dbg_buf, "width: %d\n", inst->prop.width[CAPTURE_PORT]);
+ write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
+ write_str(&dbg_buf, "state: %d\n", inst->state);
+ write_str(&dbg_buf, "secure: %d\n", !!(inst->flags & VIDC_SECURE));
+ write_str(&dbg_buf, "-----------Formats-------------\n");
+ for (i = 0; i < MAX_PORT_NUM; i++) {
+ write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ?
+ "Output" : "Capture");
+ write_str(&dbg_buf, "name : %s\n", inst->fmts[i]->name);
+ write_str(&dbg_buf, "planes : %d\n", inst->fmts[i]->num_planes);
+ write_str(
+ &dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
+ "Output" : "Capture");
+ switch (inst->buffer_mode_set[i]) {
+ case HAL_BUFFER_MODE_STATIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "static");
+ break;
+ case HAL_BUFFER_MODE_RING:
+ write_str(&dbg_buf, "buffer mode : %s\n", "ring");
+ break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "dynamic");
+ break;
+ default:
+ write_str(&dbg_buf, "buffer mode : unsupported\n");
+ }
+
+ write_str(&dbg_buf, "count: %u\n",
+ inst->bufq[i].vb2_bufq.num_buffers);
+
+ for (j = 0; j < inst->fmts[i]->num_planes; j++)
+ write_str(&dbg_buf, "size for plane %d: %u\n", j,
+ inst->bufq[i].vb2_bufq.plane_sizes[j]);
+
+ if (i < MAX_PORT_NUM - 1)
+ write_str(&dbg_buf, "\n");
+ }
+ write_str(&dbg_buf, "-------------------------------\n");
+ for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
+ write_str(&dbg_buf, "completions[%d]: %s\n", i,
+ completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
+ "pending" : "done");
+ }
+ write_str(&dbg_buf, "ETB Count: %d\n", inst->count.etb);
+ write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
+ write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
+ write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
+
+ publish_unreleased_reference(inst);
+
+ return simple_read_from_buffer(buf, count, ppos,
+ dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations inst_info_fops = {
+ .open = inst_info_open,
+ .read = inst_info_read,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+ struct dentry *parent)
+{
+ struct dentry *dir = NULL;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst);
+ goto failed_create_dir;
+ }
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
+ dir = debugfs_create_dir(debugfs_name, parent);
+ if (!dir) {
+ dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_file("info", S_IRUGO, dir, inst, &inst_info_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+ inst->debug.pdata[FRAME_PROCESSING].sampling = true;
+failed_create_dir:
+ return dir;
+}
+
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+ enum msm_vidc_debugfs_event e)
+{
+ struct msm_vidc_debug *d = &inst->debug;
+ char a[64] = "Frame processing";
+ switch (e) {
+ case MSM_VIDC_DEBUGFS_EVENT_ETB:
+ mutex_lock(&inst->lock);
+ inst->count.etb++;
+ mutex_unlock(&inst->lock);
+ if (inst->count.ebd && inst->count.ftb > inst->count.fbd) {
+ d->pdata[FRAME_PROCESSING].name[0] = '\0';
+ tic(inst, FRAME_PROCESSING, a);
+ }
+ break;
+ case MSM_VIDC_DEBUGFS_EVENT_EBD:
+ mutex_lock(&inst->lock);
+ inst->count.ebd++;
+ mutex_unlock(&inst->lock);
+ if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
+ toc(inst, FRAME_PROCESSING);
+ dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
+ }
+ if (inst->count.ftb == inst->count.fbd)
+ dprintk(VIDC_PROF, "EBD: FW needs output buffers\n");
+ break;
+ case MSM_VIDC_DEBUGFS_EVENT_FTB: {
+ inst->count.ftb++;
+ if (inst->count.ebd && inst->count.etb > inst->count.ebd) {
+ d->pdata[FRAME_PROCESSING].name[0] = '\0';
+ tic(inst, FRAME_PROCESSING, a);
+ }
+ }
+ break;
+ case MSM_VIDC_DEBUGFS_EVENT_FBD:
+ inst->debug.samples++;
+ if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
+ toc(inst, FRAME_PROCESSING);
+ dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
+ }
+ if (inst->count.etb == inst->count.ebd)
+ dprintk(VIDC_PROF, "FBD: FW needs input buffers\n");
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e);
+ break;
+ }
+}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
new file mode 100644
index 000000000000..a72691077250
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include "msm_vidc_internal.h"
+#include "trace/events/msm_vidc.h"
+
+#ifndef VIDC_DBG_LABEL
+#define VIDC_DBG_LABEL "msm_vidc"
+#endif
+
+#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: "
+
+/* To enable messages OR these values and
+ * echo the result to debugfs file.
+ *
+ * To enable all messages set debug_level = 0x101F
+ */
+
+enum vidc_msg_prio {
+ VIDC_ERR = 0x0001,
+ VIDC_WARN = 0x0002,
+ VIDC_INFO = 0x0004,
+ VIDC_DBG = 0x0008,
+ VIDC_PROF = 0x0010,
+ VIDC_PKT = 0x0020,
+ VIDC_FW = 0x1000,
+};
+
+enum vidc_msg_out {
+ VIDC_OUT_PRINTK = 0,
+ VIDC_OUT_FTRACE,
+};
+
+enum msm_vidc_debugfs_event {
+ MSM_VIDC_DEBUGFS_EVENT_ETB,
+ MSM_VIDC_DEBUGFS_EVENT_EBD,
+ MSM_VIDC_DEBUGFS_EVENT_FTB,
+ MSM_VIDC_DEBUGFS_EVENT_FBD,
+};
+
+extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
+extern int msm_vidc_fw_debug;
+extern int msm_vidc_fw_debug_mode;
+extern int msm_vidc_fw_low_power_mode;
+extern int msm_vidc_hw_rsp_timeout;
+extern int msm_vidc_fw_coverage;
+extern int msm_vidc_vpe_csc_601_to_709;
+extern int msm_vidc_dec_dcvs_mode;
+extern int msm_vidc_enc_dcvs_mode;
+extern int msm_vidc_sys_idle_indicator;
+extern int msm_vidc_firmware_unload_delay;
+extern int msm_vidc_thermal_mitigation_disabled;
+
+#define VIDC_MSG_PRIO2STRING(__level) ({ \
+ char *__str; \
+ \
+ switch (__level) { \
+ case VIDC_ERR: \
+ __str = "err"; \
+ break; \
+ case VIDC_WARN: \
+ __str = "warn"; \
+ break; \
+ case VIDC_INFO: \
+ __str = "info"; \
+ break; \
+ case VIDC_DBG: \
+ __str = "dbg"; \
+ break; \
+ case VIDC_PROF: \
+ __str = "prof"; \
+ break; \
+ case VIDC_PKT: \
+ __str = "pkt"; \
+ break; \
+ case VIDC_FW: \
+ __str = "fw"; \
+ break; \
+ default: \
+ __str = "????"; \
+ break; \
+ } \
+ \
+ __str; \
+ })
+
+#define dprintk(__level, __fmt, arg...) \
+ do { \
+ if (msm_vidc_debug & __level) { \
+ if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+ pr_info(VIDC_DBG_TAG __fmt, \
+ VIDC_MSG_PRIO2STRING(__level), \
+ ## arg); \
+ } else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+ trace_printk(KERN_DEBUG VIDC_DBG_TAG __fmt, \
+ VIDC_MSG_PRIO2STRING(__level), \
+ ## arg); \
+ } \
+ } \
+ } while (0)
+
+
+
+struct dentry *msm_vidc_debugfs_init_drv(void);
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+ struct dentry *parent);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+ struct dentry *parent);
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+ enum msm_vidc_debugfs_event e);
+
+static inline void tic(struct msm_vidc_inst *i, enum profiling_points p,
+ char *b)
+{
+ struct timeval __ddl_tv;
+ if (!i->debug.pdata[p].name[0])
+ memcpy(i->debug.pdata[p].name, b, 64);
+ if ((msm_vidc_debug & VIDC_PROF) &&
+ i->debug.pdata[p].sampling) {
+ do_gettimeofday(&__ddl_tv);
+ i->debug.pdata[p].start =
+ (__ddl_tv.tv_sec * 1000) + (__ddl_tv.tv_usec / 1000);
+ i->debug.pdata[p].sampling = false;
+ }
+}
+
+static inline void toc(struct msm_vidc_inst *i, enum profiling_points p)
+{
+ struct timeval __ddl_tv;
+ if ((msm_vidc_debug & VIDC_PROF) &&
+ !i->debug.pdata[p].sampling) {
+ do_gettimeofday(&__ddl_tv);
+ i->debug.pdata[p].stop = (__ddl_tv.tv_sec * 1000)
+ + (__ddl_tv.tv_usec / 1000);
+ i->debug.pdata[p].cumulative += i->debug.pdata[p].stop -
+ i->debug.pdata[p].start;
+ i->debug.pdata[p].sampling = true;
+ }
+}
+
+static inline void show_stats(struct msm_vidc_inst *i)
+{
+ int x;
+ for (x = 0; x < MAX_PROFILING_POINTS; x++) {
+ if (i->debug.pdata[x].name[0] &&
+ (msm_vidc_debug & VIDC_PROF)) {
+ if (i->debug.samples) {
+ dprintk(VIDC_PROF, "%s averaged %d ms/sample\n",
+ i->debug.pdata[x].name,
+ i->debug.pdata[x].cumulative /
+ i->debug.samples);
+ }
+
+ dprintk(VIDC_PROF, "%s Samples: %d\n",
+ i->debug.pdata[x].name,
+ i->debug.samples);
+ }
+ }
+}
+
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
new file mode 100644
index 000000000000..c1bdeda472b8
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -0,0 +1,382 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <soc/qcom/ocmem.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/msm_vidc.h>
+#include <media/msm_media_info.h>
+
+#include "vidc_hfi_api.h"
+#include "vidc_hfi_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(1, 0, 0);
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+#define DEFAULT_HEIGHT 1088
+#define DEFAULT_WIDTH 1920
+#define MIN_SUPPORTED_WIDTH 32
+#define MIN_SUPPORTED_HEIGHT 32
+
+/* Maintains the number of FTB's between each FBD over a window */
+#define DCVS_FTB_WINDOW 32
+
+#define V4L2_EVENT_VIDC_BASE 10
+
+#define SYS_MSG_START VIDC_EVENT_CHANGE
+#define SYS_MSG_END SYS_DEBUG
+#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
+#define SESSION_MSG_END SESSION_PROPERTY_INFO
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+#define MAX_NAME_LENGTH 64
+
+#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0)
+
+#define NUM_MBS_PER_SEC(__height, __width, __fps) \
+ (NUM_MBS_PER_FRAME(__height, __width) * __fps)
+
+#define NUM_MBS_PER_FRAME(__height, __width) \
+ ((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16))
+
+enum vidc_ports {
+ OUTPUT_PORT,
+ CAPTURE_PORT,
+ MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+ VIDC_CORE_UNINIT = 0,
+ VIDC_CORE_LOADED,
+ VIDC_CORE_INIT,
+ VIDC_CORE_INIT_DONE,
+ VIDC_CORE_INVALID
+};
+
+/* Do not change the enum values unless
+ * you know what you are doing*/
+enum instance_state {
+ MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+ MSM_VIDC_CORE_INIT,
+ MSM_VIDC_CORE_INIT_DONE,
+ MSM_VIDC_OPEN,
+ MSM_VIDC_OPEN_DONE,
+ MSM_VIDC_LOAD_RESOURCES,
+ MSM_VIDC_LOAD_RESOURCES_DONE,
+ MSM_VIDC_START,
+ MSM_VIDC_START_DONE,
+ MSM_VIDC_STOP,
+ MSM_VIDC_STOP_DONE,
+ MSM_VIDC_RELEASE_RESOURCES,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ MSM_VIDC_CLOSE,
+ MSM_VIDC_CLOSE_DONE,
+ MSM_VIDC_CORE_UNINIT,
+ MSM_VIDC_CORE_INVALID
+};
+
+struct buf_info {
+ struct list_head list;
+ struct vb2_buffer *buf;
+};
+
+struct msm_vidc_list {
+ struct list_head list;
+ struct mutex lock;
+};
+
+static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
+{
+ mutex_init(&mlist->lock);
+ INIT_LIST_HEAD(&mlist->list);
+}
+
+enum buffer_owner {
+ DRIVER,
+ FIRMWARE,
+ CLIENT,
+ MAX_OWNER
+};
+
+struct internal_buf {
+ struct list_head list;
+ enum hal_buffer buffer_type;
+ struct msm_smem *handle;
+ enum buffer_owner buffer_ownership;
+};
+
+struct msm_vidc_format {
+ char name[MAX_NAME_LENGTH];
+ u8 description[32];
+ u32 fourcc;
+ int num_planes;
+ int type;
+ u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+ struct mutex lock;
+ struct list_head cores;
+ int num_cores;
+ struct dentry *debugfs_root;
+ int thermal_level;
+};
+
+struct msm_video_device {
+ int type;
+ struct video_device vdev;
+};
+
+struct session_prop {
+ u32 width[MAX_PORT_NUM];
+ u32 height[MAX_PORT_NUM];
+ u32 fps;
+ u32 bitrate;
+};
+
+struct buf_queue {
+ struct vb2_queue vb2_bufq;
+ struct mutex lock;
+};
+
+enum profiling_points {
+ SYS_INIT = 0,
+ SESSION_INIT,
+ LOAD_RESOURCES,
+ FRAME_PROCESSING,
+ FW_IDLE,
+ MAX_PROFILING_POINTS,
+};
+
+struct buf_count {
+ int etb;
+ int ftb;
+ int fbd;
+ int ebd;
+};
+
+struct dcvs_stats {
+ int num_ftb[DCVS_FTB_WINDOW];
+ bool transition_turbo;
+ int ftb_index;
+ int ftb_counter;
+ bool prev_freq_lowered;
+ bool prev_freq_increased;
+ int threshold_disp_buf_high;
+ int threshold_disp_buf_low;
+ int load;
+ int load_low;
+ int load_high;
+ int min_threshold;
+ int max_threshold;
+ bool is_clock_scaled;
+ int etb_counter;
+ bool is_power_save_mode;
+ bool is_output_buff_added;
+ bool is_input_buff_added;
+ bool is_additional_buff_added;
+};
+
+struct profile_data {
+ int start;
+ int stop;
+ int cumulative;
+ char name[64];
+ int sampling;
+ int average;
+};
+
+struct msm_vidc_debug {
+ struct profile_data pdata[MAX_PROFILING_POINTS];
+ int profile;
+ int samples;
+};
+
+enum msm_vidc_modes {
+ VIDC_SECURE = 1 << 0,
+ VIDC_TURBO = 1 << 1,
+ VIDC_THUMBNAIL = 1 << 2,
+ VIDC_NOMINAL = 1 << 3,
+};
+
+struct msm_vidc_core_capability {
+ struct hal_capability_supported width;
+ struct hal_capability_supported height;
+ struct hal_capability_supported frame_rate;
+ u32 pixelprocess_capabilities;
+ struct hal_capability_supported scale_x;
+ struct hal_capability_supported scale_y;
+ struct hal_capability_supported hier_p;
+ struct hal_capability_supported ltr_count;
+ struct hal_capability_supported mbs_per_frame;
+ struct hal_capability_supported secure_output2_threshold;
+ u32 capability_set;
+ enum buffer_mode_type buffer_mode[MAX_PORT_NUM];
+ u32 buffer_size_limit;
+};
+
+struct msm_vidc_core {
+ struct list_head list;
+ struct mutex lock;
+ int id;
+ void *device;
+ struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+ struct v4l2_device v4l2_dev;
+ struct list_head instances;
+ struct dentry *debugfs_root;
+ enum vidc_core_state state;
+ struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+ enum msm_vidc_hfi_type hfi_type;
+ struct msm_vidc_platform_resources resources;
+ u32 enc_codec_supported;
+ u32 dec_codec_supported;
+ struct delayed_work fw_unload_work;
+};
+
+struct msm_vidc_inst {
+ struct list_head list;
+ struct mutex sync_lock, lock;
+ struct msm_vidc_core *core;
+ enum session_type session_type;
+ void *session;
+ struct session_prop prop;
+ enum instance_state state;
+ struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct buf_queue bufq[MAX_PORT_NUM];
+ struct msm_vidc_list pendingq;
+ struct msm_vidc_list internalbufs;
+ struct msm_vidc_list persistbufs;
+ struct msm_vidc_list pending_getpropq;
+ struct msm_vidc_list outputbufs;
+ struct msm_vidc_list registeredbufs;
+ struct buffer_requirements buff_req;
+ void *mem_client;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+ struct v4l2_ctrl **cluster;
+ struct v4l2_fh event_handler;
+ struct msm_smem *extradata_handle;
+ bool in_reconfig;
+ u32 reconfig_width;
+ u32 reconfig_height;
+ struct dentry *debugfs_root;
+ struct vb2_buffer *vb2_seq_hdr;
+ void *priv;
+ struct msm_vidc_debug debug;
+ struct buf_count count;
+ struct dcvs_stats dcvs;
+ enum msm_vidc_modes flags;
+ struct msm_vidc_core_capability capability;
+ enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+ bool map_output_buffer;
+ atomic_t seq_hdr_reqs;
+ struct v4l2_ctrl **ctrls;
+ bool dcvs_mode;
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl_cluster {
+ struct v4l2_ctrl **cluster;
+ struct list_head list;
+};
+
+struct msm_vidc_ctrl {
+ u32 id;
+ char name[MAX_NAME_LENGTH];
+ enum v4l2_ctrl_type type;
+ s32 minimum;
+ s32 maximum;
+ s32 default_value;
+ u32 step;
+ u32 menu_skip_mask;
+ u32 flags;
+ const char * const *qmenu;
+};
+
+void handle_cmd_response(enum command_response cmd, void *data);
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+ enum hal_ssr_trigger_type type);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int num_planes;
+ int fd[VIDEO_MAX_PLANES];
+ int buff_off[VIDEO_MAX_PLANES];
+ int size[VIDEO_MAX_PLANES];
+ unsigned long uvaddr[VIDEO_MAX_PLANES];
+ ion_phys_addr_t device_addr[VIDEO_MAX_PLANES];
+ struct msm_smem *handle[VIDEO_MAX_PLANES];
+ enum v4l2_memory memory;
+ u32 v4l2_index;
+ bool pending_deletion;
+ atomic_t ref_count;
+ bool dequeued;
+ bool inactive;
+ bool mapped[VIDEO_MAX_PLANES];
+ int same_fd_ref[VIDEO_MAX_PLANES];
+ struct timeval timestamp;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+ ion_phys_addr_t device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+struct buffer_info *get_registered_mmap_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b, int *plane);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+
+void msm_comm_handle_thermal_event(void);
+void *msm_smem_new_client(enum smem_type mtype,
+ void *platform_resources);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+ enum hal_buffer buffer_type);
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+ bool is_secure, enum hal_buffer buffer_type);
+void msm_vidc_fw_unload_handler(struct work_struct *work);
+struct msm_smem* msm_smem_map_dma_buf(void* smem_client,
+ struct dma_buf* dbuf, enum hal_buffer type);
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
new file mode 100644
index 000000000000..79ceaedbacf7
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -0,0 +1,963 @@
+/* Copyright (c) 2012-2015, 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 <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/qcom_iommu.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <media/videobuf2-dma-contig.h>
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+#include "msm_vidc_res_parse.h"
+#include "venus_boot.h"
+
+enum clock_properties {
+ CLOCK_PROP_HAS_SCALING = 1 << 0,
+};
+
+static size_t get_u32_array_num_elements(struct platform_device *pdev,
+ char *name)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int len;
+ size_t num_elements = 0;
+ if (!of_get_property(np, name, &len)) {
+ dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
+ name);
+ goto fail_read;
+ }
+
+ num_elements = len / sizeof(u32);
+ if (num_elements <= 0) {
+ dprintk(VIDC_ERR, "%s not specified in device tree\n",
+ name);
+ goto fail_read;
+ }
+ return num_elements;
+
+fail_read:
+ return 0;
+}
+
+static inline enum imem_type read_imem_type(struct platform_device *pdev)
+{
+ bool is_compatible(char *compat)
+ {
+ return !!of_find_compatible_node(NULL, NULL, compat);
+ }
+
+ return is_compatible("qcom,msm-ocmem") ? IMEM_OCMEM :
+ is_compatible("qcom,msm-vmem") ? IMEM_VMEM :
+ IMEM_NONE;
+
+}
+
+int read_hfi_type(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int rc = 0;
+ const char *hfi_name = NULL;
+
+ if (np) {
+ rc = of_property_read_string(np, "qcom,hfi", &hfi_name);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to read hfi from device tree\n");
+ goto err_hfi_read;
+ }
+ if (!strcasecmp(hfi_name, "venus"))
+ rc = VIDC_HFI_VENUS;
+ else if (!strcasecmp(hfi_name, "q6"))
+ rc = VIDC_HFI_Q6;
+ else
+ rc = -EINVAL;
+ } else
+ rc = VIDC_HFI_Q6;
+
+err_hfi_read:
+ return rc;
+}
+
+static inline void msm_vidc_free_freq_table(
+ struct msm_vidc_platform_resources *res)
+{
+ res->load_freq_tbl = NULL;
+}
+
+static inline void msm_vidc_free_reg_table(
+ struct msm_vidc_platform_resources *res)
+{
+ res->reg_set.reg_tbl = NULL;
+}
+
+static inline void msm_vidc_free_qdss_addr_table(
+ struct msm_vidc_platform_resources *res)
+{
+ res->qdss_addr_set.addr_tbl = NULL;
+}
+
+static inline void msm_vidc_free_bus_vectors(
+ struct msm_vidc_platform_resources *res)
+{
+ int i = 0;
+ for (i = 0; i < res->bus_set.count; i++) {
+ if (res->bus_set.bus_tbl[i].pdata)
+ msm_bus_cl_clear_pdata(res->bus_set.bus_tbl[i].pdata);
+ }
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
+static inline void msm_vidc_free_regulator_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int c = 0;
+ for (c = 0; c < res->regulator_set.count; ++c) {
+ struct regulator_info *rinfo =
+ &res->regulator_set.regulator_tbl[c];
+
+ kfree(rinfo->name);
+ rinfo->name = NULL;
+ }
+
+ /* The regulator table is one the few allocs that aren't managed, hence
+ * free it manually */
+ kfree(res->regulator_set.regulator_tbl);
+ res->regulator_set.regulator_tbl = NULL;
+ res->regulator_set.count = 0;
+}
+
+static inline void msm_vidc_free_clock_table(
+ struct msm_vidc_platform_resources *res)
+{
+ res->clock_set.clock_tbl = NULL;
+ res->clock_set.count = 0;
+}
+
+void msm_vidc_free_platform_resources(
+ struct msm_vidc_platform_resources *res)
+{
+ msm_vidc_free_clock_table(res);
+ msm_vidc_free_regulator_table(res);
+ msm_vidc_free_freq_table(res);
+ msm_vidc_free_reg_table(res);
+ msm_vidc_free_qdss_addr_table(res);
+ msm_vidc_free_bus_vectors(res);
+ msm_vidc_free_buffer_usage_table(res);
+}
+
+static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
+{
+ struct reg_set *reg_set;
+ struct platform_device *pdev = res->pdev;
+ int i;
+ int rc = 0;
+
+ if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) {
+ /* qcom,reg-presets is an optional property. It likely won't be
+ * present if we don't have any register settings to program */
+ dprintk(VIDC_DBG, "qcom,reg-presets not found\n");
+ return 0;
+ }
+
+ reg_set = &res->reg_set;
+ reg_set->count = get_u32_array_num_elements(pdev, "qcom,reg-presets");
+ reg_set->count /= sizeof(*reg_set->reg_tbl) / sizeof(u32);
+
+ if (!reg_set->count) {
+ dprintk(VIDC_DBG, "no elements in reg set\n");
+ return rc;
+ }
+
+ reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count *
+ sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
+ if (!reg_set->reg_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
+ (u32 *)reg_set->reg_tbl, reg_set->count * 2)) {
+ dprintk(VIDC_ERR, "Failed to read register table\n");
+ msm_vidc_free_reg_table(res);
+ return -EINVAL;
+ }
+ for (i = 0; i < reg_set->count; i++) {
+ dprintk(VIDC_DBG,
+ "reg = %x, value = %x\n",
+ reg_set->reg_tbl[i].reg,
+ reg_set->reg_tbl[i].value
+ );
+ }
+ return rc;
+}
+static int msm_vidc_load_qdss_table(struct msm_vidc_platform_resources *res)
+{
+ struct addr_set *qdss_addr_set;
+ struct platform_device *pdev = res->pdev;
+ int i;
+ int rc = 0;
+
+ if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) {
+ /* qcom,qdss-presets is an optional property. It likely won't be
+ * present if we don't have any register settings to program */
+ dprintk(VIDC_DBG, "qcom,qdss-presets not found\n");
+ return rc;
+ }
+
+ qdss_addr_set = &res->qdss_addr_set;
+ qdss_addr_set->count = get_u32_array_num_elements(pdev,
+ "qcom,qdss-presets");
+ qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32);
+
+ if (!qdss_addr_set->count) {
+ dprintk(VIDC_DBG, "no elements in qdss reg set\n");
+ return rc;
+ }
+
+ qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev,
+ qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl),
+ GFP_KERNEL);
+ if (!qdss_addr_set->addr_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_qdss_addr_tbl;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets",
+ (u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read qdss address table\n");
+ msm_vidc_free_qdss_addr_table(res);
+ rc = -EINVAL;
+ goto err_qdss_addr_tbl;
+ }
+
+ for (i = 0; i < qdss_addr_set->count; i++) {
+ dprintk(VIDC_DBG, "qdss addr = %x, value = %x\n",
+ qdss_addr_set->addr_tbl[i].start,
+ qdss_addr_set->addr_tbl[i].size);
+ }
+err_qdss_addr_tbl:
+ return rc;
+}
+
+static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ int num_elements = 0;
+ struct platform_device *pdev = res->pdev;
+
+ /* A comparator to compare loads (needed later on) */
+ int cmp(const void *a, const void *b)
+ {
+ /* want to sort in reverse so flip the comparison */
+ return ((struct load_freq_table *)b)->load -
+ ((struct load_freq_table *)a)->load;
+ }
+
+ if (!of_find_property(pdev->dev.of_node, "qcom,load-freq-tbl", NULL)) {
+ /* qcom,load-freq-tbl is an optional property. It likely won't
+ * be present on cores that we can't clock scale on. */
+ dprintk(VIDC_DBG, "qcom,load-freq-tbl not found\n");
+ return 0;
+ }
+
+ num_elements = get_u32_array_num_elements(pdev, "qcom,load-freq-tbl");
+ num_elements /= sizeof(*res->load_freq_tbl) / sizeof(u32);
+ if (!num_elements) {
+ dprintk(VIDC_ERR, "no elements in frequency table\n");
+ return rc;
+ }
+
+ res->load_freq_tbl = devm_kzalloc(&pdev->dev, num_elements *
+ sizeof(*res->load_freq_tbl), GFP_KERNEL);
+ if (!res->load_freq_tbl) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc load_freq_tbl\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,load-freq-tbl", (u32 *)res->load_freq_tbl,
+ num_elements * sizeof(*res->load_freq_tbl) / sizeof(u32))) {
+ dprintk(VIDC_ERR, "Failed to read frequency table\n");
+ msm_vidc_free_freq_table(res);
+ return -EINVAL;
+ }
+
+ res->load_freq_tbl_size = num_elements;
+
+ /* The entries in the DT might not be sorted (for aesthetic purposes).
+ * Given that we expect the loads in descending order for our scaling
+ * logic to work, just sort it ourselves
+ */
+ sort(res->load_freq_tbl, res->load_freq_tbl_size,
+ sizeof(*res->load_freq_tbl), cmp, NULL);
+ return rc;
+}
+
+static int msm_vidc_load_bus_vectors(struct msm_vidc_platform_resources *res)
+{
+ struct platform_device *pdev = res->pdev;
+ struct device_node *child_node, *bus_node;
+ struct bus_set *buses = &res->bus_set;
+ int rc = 0, c = 0;
+ u32 num_buses = 0;
+
+ bus_node = of_find_node_by_name(pdev->dev.of_node,
+ "qcom,msm-bus-clients");
+ if (!bus_node) {
+ /* Not a required property */
+ dprintk(VIDC_DBG, "qcom,msm-bus-clients not found\n");
+ rc = 0;
+ goto err_bad_node;
+ }
+
+ for_each_child_of_node(bus_node, child_node)
+ ++num_buses;
+
+ buses->bus_tbl = devm_kzalloc(&pdev->dev, sizeof(*buses->bus_tbl) *
+ num_buses, GFP_KERNEL);
+ if (!buses->bus_tbl) {
+ dprintk(VIDC_ERR, "%s: Failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto err_bad_node;
+ }
+
+ buses->count = num_buses;
+ c = 0;
+
+ for_each_child_of_node(bus_node, child_node) {
+ bool passive = false;
+ u32 configs = 0;
+ struct bus_info *bus = &buses->bus_tbl[c];
+
+ passive = of_property_read_bool(child_node, "qcom,bus-passive");
+ rc = of_property_read_u32(child_node, "qcom,bus-configs",
+ &configs);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to read qcom,bus-configs in %s: %d\n",
+ child_node->name, rc);
+ break;
+ }
+
+ bus->passive = passive;
+ bus->sessions_supported = configs;
+ bus->pdata = msm_bus_pdata_from_node(pdev, child_node);
+ if (IS_ERR_OR_NULL(bus->pdata)) {
+ rc = PTR_ERR(bus->pdata) ?: -EBADHANDLE;
+ dprintk(VIDC_ERR, "Failed to get bus pdata: %d\n", rc);
+ break;
+ }
+
+ dprintk(VIDC_DBG, "Bus %s supports: %x, passive: %d\n",
+ bus->pdata->name, bus->sessions_supported,
+ passive);
+ ++c;
+ }
+
+ if (c < num_buses) {
+ for (c--; c >= 0; c--)
+ msm_bus_cl_clear_pdata(buses->bus_tbl[c].pdata);
+
+ goto err_bad_node;
+ }
+
+err_bad_node:
+ return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+ if (!of_find_property(pdev->dev.of_node,
+ "qcom,buffer-type-tz-usage-table", NULL)) {
+ /* qcom,buffer-type-tz-usage-table is an optional property. It
+ * likely won't be present if the core doesn't support content
+ * protection */
+ dprintk(VIDC_DBG, "buffer-type-tz-usage-table not found\n");
+ return 0;
+ }
+
+ buffer_usage_set->count = get_u32_array_num_elements(
+ pdev, "qcom,buffer-type-tz-usage-table");
+ buffer_usage_set->count /=
+ sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32);
+ if (!buffer_usage_set->count) {
+ dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+ return 0;
+ }
+
+ buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev,
+ buffer_usage_set->count *
+ sizeof(*buffer_usage_set->buffer_usage_tbl),
+ GFP_KERNEL);
+ if (!buffer_usage_set->buffer_usage_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_load_buf_usage;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,buffer-type-tz-usage-table",
+ (u32 *)buffer_usage_set->buffer_usage_tbl,
+ buffer_usage_set->count *
+ sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32));
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+ goto err_load_buf_usage;
+ }
+
+ return 0;
+err_load_buf_usage:
+ msm_vidc_free_buffer_usage_table(res);
+ return rc;
+}
+
+static int msm_vidc_load_regulator_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct regulator_set *regulators = &res->regulator_set;
+ struct device_node *domains_parent_node = NULL;
+ struct property *domains_property = NULL;
+
+ regulators->count = 0;
+ regulators->regulator_tbl = NULL;
+
+ domains_parent_node = pdev->dev.of_node;
+ for_each_property_of_node(domains_parent_node, domains_property) {
+ const char *search_string = "-supply";
+ char *supply;
+ bool matched = false;
+ struct device_node *regulator_node = NULL;
+ struct regulator_info *rinfo = NULL;
+ void *temp = NULL;
+
+ /* 1) check if current property is possibly a regulator */
+ supply = strnstr(domains_property->name, search_string,
+ strlen(domains_property->name) + 1);
+ matched = supply && (*(supply + strlen(search_string)) == '\0');
+ if (!matched)
+ continue;
+
+ /* 2) make sure prop isn't being misused */
+ regulator_node = of_parse_phandle(domains_parent_node,
+ domains_property->name, 0);
+ if (IS_ERR(regulator_node)) {
+ dprintk(VIDC_WARN, "%s is not a phandle\n",
+ domains_property->name);
+ continue;
+ }
+
+ /* 3) expand our table */
+ temp = krealloc(regulators->regulator_tbl,
+ sizeof(*regulators->regulator_tbl) *
+ (regulators->count + 1), GFP_KERNEL);
+ if (!temp) {
+ rc = -ENOMEM;
+ dprintk(VIDC_ERR,
+ "Failed to alloc memory for regulator table\n");
+ goto err_reg_tbl_alloc;
+ }
+
+ regulators->regulator_tbl = temp;
+ regulators->count++;
+
+ /* 4) populate regulator info */
+ rinfo = &regulators->regulator_tbl[regulators->count - 1];
+ rinfo->name = kstrndup(domains_property->name,
+ supply - domains_property->name, GFP_KERNEL);
+ if (!rinfo->name) {
+ rc = -ENOMEM;
+ dprintk(VIDC_ERR,
+ "Failed to alloc memory for regulator name\n");
+ goto err_reg_name_alloc;
+ }
+
+ rinfo->has_hw_power_collapse = of_property_read_bool(
+ regulator_node, "qcom,support-hw-trigger");
+
+ dprintk(VIDC_DBG, "Found regulator %s: h/w collapse = %s\n",
+ rinfo->name,
+ rinfo->has_hw_power_collapse ? "yes" : "no");
+ }
+
+ if (!regulators->count)
+ dprintk(VIDC_DBG, "No regulators found");
+
+ return 0;
+
+err_reg_name_alloc:
+err_reg_tbl_alloc:
+ msm_vidc_free_regulator_table(res);
+ return rc;
+}
+
+static int msm_vidc_load_clock_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0, num_clocks = 0, c = 0;
+ struct platform_device *pdev = res->pdev;
+ int *clock_props = NULL;
+ struct clock_set *clocks = &res->clock_set;
+
+ num_clocks = of_property_count_strings(pdev->dev.of_node,
+ "clock-names");
+ if (num_clocks <= 0) {
+ /* Devices such as Q6 might not have any control over clocks
+ * hence have none specified, which is ok. */
+ dprintk(VIDC_DBG, "No clocks found\n");
+ clocks->count = 0;
+ rc = 0;
+ goto err_load_clk_table_fail;
+ }
+
+ clock_props = devm_kzalloc(&pdev->dev, num_clocks *
+ sizeof(*clock_props), GFP_KERNEL);
+ if (!clock_props) {
+ dprintk(VIDC_ERR, "No memory to read clock properties\n");
+ rc = -ENOMEM;
+ goto err_load_clk_table_fail;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,clock-configs", clock_props,
+ num_clocks);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read clock properties: %d\n", rc);
+ goto err_load_clk_prop_fail;
+ }
+
+ clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl)
+ * num_clocks, GFP_KERNEL);
+ if (!clocks->clock_tbl) {
+ dprintk(VIDC_ERR, "Failed to allocate memory for clock tbl\n");
+ rc = -ENOMEM;
+ goto err_load_clk_prop_fail;
+ }
+
+ clocks->count = num_clocks;
+ dprintk(VIDC_DBG, "Found %d clocks\n", num_clocks);
+
+ for (c = 0; c < num_clocks; ++c) {
+ struct clock_info *vc = &res->clock_set.clock_tbl[c];
+
+ of_property_read_string_index(pdev->dev.of_node,
+ "clock-names", c, &vc->name);
+
+ if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
+ vc->count = res->load_freq_tbl_size;
+ vc->load_freq_tbl = res->load_freq_tbl;
+ } else {
+ vc->count = 0;
+ vc->load_freq_tbl = NULL;
+ }
+
+ dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name,
+ vc->count ? "yes" : "no");
+ }
+
+
+ return 0;
+
+err_load_clk_prop_fail:
+err_load_clk_table_fail:
+ return rc;
+}
+
+int read_platform_resources_from_dt(
+ struct msm_vidc_platform_resources *res)
+{
+ struct platform_device *pdev = res->pdev;
+ struct resource *kres = NULL;
+ int rc = 0;
+ uint32_t firmware_base = 0;
+
+ if (!pdev->dev.of_node) {
+ dprintk(VIDC_ERR, "DT node not found\n");
+ return -ENOENT;
+ }
+
+ INIT_LIST_HEAD(&res->context_banks);
+
+ res->firmware_base = (phys_addr_t)firmware_base;
+
+ kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res->register_base = kres ? kres->start : -1;
+ res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
+
+ kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ res->irq = kres ? kres->start : -1;
+
+ of_property_read_u32(pdev->dev.of_node,
+ "qcom,imem-size", &res->imem_size);
+ res->imem_type = read_imem_type(pdev);
+
+ res->sys_idle_indicator = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-idle-indicator");
+
+ res->thermal_mitigable =
+ of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-thermal-mitigation");
+
+ rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+ &res->fw_name);
+ if (rc)
+ dprintk(VIDC_WARN, "Failed to read firmware name: %d\n", rc);
+
+ dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
+
+ rc = of_property_read_string(pdev->dev.of_node, "qcom,hfi-version",
+ &res->hfi_version);
+ if (rc)
+ dprintk(VIDC_DBG, "HFI packetization will default to legacy\n");
+
+ rc = msm_vidc_load_freq_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
+ goto err_load_freq_table;
+ }
+
+ rc = msm_vidc_load_qdss_table(res);
+ if (rc)
+ dprintk(VIDC_WARN, "Failed to load qdss reg table: %d\n", rc);
+
+ rc = msm_vidc_load_reg_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
+ goto err_load_reg_table;
+ }
+#if 0
+ rc = msm_vidc_load_bus_vectors(res);
+#else
+ rc = 0;
+#endif
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
+ goto err_load_bus_vectors;
+ }
+
+ rc = msm_vidc_load_buffer_usage_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to load buffer usage table: %d\n", rc);
+ goto err_load_buffer_usage_table;
+ }
+
+ rc = msm_vidc_load_regulator_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load list of regulators %d\n", rc);
+ goto err_load_regulator_table;
+ }
+
+ rc = msm_vidc_load_clock_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to load clock table: %d\n", rc);
+ goto err_load_clock_table;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+ &res->max_load);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to determine max load supported: %d\n", rc);
+ goto err_load_max_hw_load;
+ }
+
+ res->use_non_secure_pil = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-non-secure-pil");
+
+ if (res->use_non_secure_pil || !is_iommu_present(res)) {
+ of_property_read_u32(pdev->dev.of_node, "qcom,fw-bias",
+ &firmware_base);
+ res->firmware_base = (phys_addr_t)firmware_base;
+ dprintk(VIDC_DBG,
+ "Using fw-bias : %pa", &res->firmware_base);
+ }
+
+ res->sw_power_collapsible = of_property_read_bool(pdev->dev.of_node,
+ "qcom,sw-power-collapse");
+ dprintk(VIDC_DBG, "Power collapse supported = %s\n",
+ res->sw_power_collapsible ? "yes" : "no");
+
+ res->early_fw_load = of_property_read_bool(pdev->dev.of_node,
+ "qcom,early-fw-load");
+ dprintk(VIDC_DBG, "Early fw load = %s\n",
+ res->early_fw_load ? "yes" : "no");
+ return rc;
+err_load_max_hw_load:
+ msm_vidc_free_clock_table(res);
+err_load_clock_table:
+ msm_vidc_free_regulator_table(res);
+err_load_regulator_table:
+ msm_vidc_free_buffer_usage_table(res);
+err_load_buffer_usage_table:
+ msm_vidc_free_bus_vectors(res);
+err_load_bus_vectors:
+ msm_vidc_free_reg_table(res);
+err_load_reg_table:
+ msm_vidc_free_freq_table(res);
+err_load_freq_table:
+ return rc;
+}
+
+static int msm_vidc_setup_context_bank(struct context_bank_info *cb, bool old_smmu)
+{
+ int rc = 0;
+ int order = 0;
+ bool disable_htw = true;
+
+ if (!cb || !cb->dev) {
+ dprintk(VIDC_ERR,
+ "%s: Invalid Input params\n", __func__);
+ return -EINVAL;
+ }
+
+ if (cb->is_secure && old_smmu) {
+ cb->mapping = arm_iommu_create_mapping(&msm_iommu_sec_bus_type,
+ cb->addr_range.start, cb->addr_range.size, order);
+ } else {
+ cb->mapping = arm_iommu_create_mapping(&platform_bus_type,
+ cb->addr_range.start, cb->addr_range.size, order);
+ }
+
+ if (IS_ERR_OR_NULL(cb->mapping)) {
+ dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__);
+ rc = PTR_ERR(cb->mapping) ?: -ENODEV;
+ goto remove_cb;
+ }
+
+ rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - Couldn't arm_iommu_attach_device\n",
+ __func__);
+ goto release_mapping;
+ }
+
+#if 0
+ rc = iommu_domain_set_attr(cb->mapping->domain,
+ DOMAIN_ATTR_COHERENT_HTW_DISABLE, &disable_htw);
+#else
+ (void) disable_htw;
+ rc = 0;
+#endif
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - disable coherent HTW failed: %s %d\n",
+ __func__, dev_name(cb->dev), rc);
+ goto detach_device;
+ }
+
+ cb->alloc_ctx = vb2_dma_contig_init_ctx(cb->dev);
+ if (IS_ERR_OR_NULL(cb->alloc_ctx)) {
+ dprintk(VIDC_ERR, "%s - Failed to init dma contig ctx\n",
+ __func__);
+ rc = PTR_ERR(cb->alloc_ctx) ?: -ENOMEM;
+ goto detach_device;
+ }
+
+ dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(cb->dev));
+ dprintk(VIDC_DBG,
+ "Context bank name: %s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %p, mapping: %p, alloc_ctx: %p",
+ cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
+ cb->addr_range.size, cb->dev, cb->mapping, cb->alloc_ctx);
+
+ return rc;
+
+detach_device:
+ arm_iommu_detach_device(cb->dev);
+release_mapping:
+ arm_iommu_release_mapping(cb->mapping);
+remove_cb:
+ return rc;
+}
+
+static int msm_vidc_populate_context_bank(struct device *dev,
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct context_bank_info *cb = NULL;
+ struct device_node *np = NULL;
+ struct device_node *phandle = NULL;
+ bool old_smmu = false;
+
+ if (!dev || !res) {
+ dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__);
+ return -EINVAL;
+ }
+
+ np = dev->of_node;
+ cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
+ if (!cb) {
+ dprintk(VIDC_ERR, "%s - Failed to allocate cb\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&cb->list);
+ list_add_tail(&cb->list, &res->context_banks);
+
+ phandle = of_parse_phandle(np, "qcom,vidc-domain-phandle", 0);
+ if (phandle) {
+ dprintk(VIDC_DBG, "QSMMU entry found\n");
+ old_smmu = true;
+ rc = of_property_read_string(phandle, "label", &cb->name);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to read cb label from phandle\n");
+ goto err_setup_cb;
+ }
+ cb->dev = msm_iommu_get_ctx(cb->name);
+ if (IS_ERR_OR_NULL(cb->dev)) {
+ dprintk(VIDC_ERR,
+ "Failed to get context bank device for %s\n",
+ cb->name);
+ rc = PTR_ERR(cb->dev) ?: -ENODEV;
+ goto err_setup_cb;
+ }
+
+ rc = of_property_read_u32_array(phandle,
+ "qcom,virtual-addr-pool",
+ (u32 *)&cb->addr_range, 2);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Could not read addr pool for context bank : %s %d\n",
+ cb->name, rc);
+ goto err_setup_cb;
+ }
+
+ cb->is_secure = of_property_read_bool(phandle,
+ "qcom,secure-domain");
+
+ rc = of_property_read_u32(np, "qcom,vidc-partition-buffer-types", &cb->buffer_type);
+ if (rc) {
+ dprintk(VIDC_ERR, "failed to load buffer_type info %d\n", rc);
+ rc = -ENOENT;
+ goto err_setup_cb;
+ }
+
+ } else {
+ cb->dev = dev;
+ rc = of_property_read_string(np, "label", &cb->name);
+ if (rc) {
+ dprintk(VIDC_DBG,
+ "Failed to read cb label from device tree\n");
+ rc = 0;
+ }
+
+ dprintk(VIDC_DBG, "%s: context bank has name %s\n", __func__, cb->name);
+ rc = of_property_read_u32_array(np, "virtual-addr-pool",
+ (u32 *)&cb->addr_range, 2);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Could not read addr pool for context bank : %s %d\n",
+ cb->name, rc);
+ goto err_setup_cb;
+ }
+
+ cb->is_secure = of_property_read_bool(np, "secure-addr-range");
+ dprintk(VIDC_DBG, "context bank %s : secure = %d\n",
+ cb->name, cb->is_secure);
+
+ /* setup buffer type for each sub device*/
+ rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type);
+ if (rc) {
+ dprintk(VIDC_ERR, "failed to load buffer_type info %d\n", rc);
+ rc = -ENOENT;
+ goto err_setup_cb;
+ }
+ }
+ dprintk(VIDC_DBG,
+ "context bank %s (dev %p) address start = %x address size = %x buffer_type = %x\n",
+ cb->name, cb->dev, cb->addr_range.start,
+ cb->addr_range.size, cb->buffer_type);
+
+ rc = msm_vidc_setup_context_bank(cb, old_smmu);
+ if (rc) {
+ dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
+ goto err_setup_cb;
+ }
+
+ return 0;
+
+err_setup_cb:
+ list_del(&cb->list);
+ return rc;
+}
+
+int msm_vidc_probe_sub_devices(struct platform_device *pdev)
+{
+ struct msm_vidc_core *core;
+ int rc = 0;
+
+ if (!pdev) {
+ dprintk(VIDC_ERR, "Invalid platform device\n");
+ return -EINVAL;
+ } else if (!pdev->dev.parent) {
+ dprintk(VIDC_ERR, "Failed to find a parent for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+
+ core = dev_get_drvdata(pdev->dev.parent);
+ if (!core) {
+ dprintk(VIDC_ERR, "Failed to find cookie in parent device %s",
+ dev_name(pdev->dev.parent));
+ return -EINVAL;
+ }
+
+ dprintk(VIDC_DBG, "Probing %s\n", dev_name(&pdev->dev));
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,fw-context-bank")) {
+ if (core->resources.use_non_secure_pil) {
+ struct context_bank_info *cb;
+
+ cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL);
+ if (!cb) {
+ dprintk(VIDC_ERR, "alloc venus cb failed\n");
+ return -ENOMEM;
+ }
+
+ cb->dev = &pdev->dev;
+ rc = venus_boot_init(&core->resources, cb);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to init non-secure PIL %d\n", rc);
+ }
+ }
+ } else {
+ rc = msm_vidc_populate_context_bank(&pdev->dev,
+ &core->resources);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to probe context bank\n");
+ else
+ dprintk(VIDC_DBG, "Successfully probed context bank\n");
+ }
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
new file mode 100644
index 000000000000..2ab53b4d6112
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
@@ -0,0 +1,28 @@
+
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef DT_PARSE
+#define DT_PARSE
+#include <linux/of.h>
+#include "msm_vidc_resources.h"
+void msm_vidc_free_platform_resources(
+ struct msm_vidc_platform_resources *res);
+
+int read_hfi_type(struct platform_device *pdev);
+
+int read_platform_resources_from_dt(
+ struct msm_vidc_platform_resources *res);
+
+int msm_vidc_probe_sub_devices(struct platform_device *pdev);
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
new file mode 100644
index 000000000000..af5e70e5ad23
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -0,0 +1,147 @@
+/* Copyright (c) 2013-2015, 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.
+ *
+ */
+
+#ifndef __MSM_VIDC_RESOURCES_H__
+#define __MSM_VIDC_RESOURCES_H__
+
+#include <linux/platform_device.h>
+#include <media/msm_vidc.h>
+#define MAX_BUFFER_TYPES 32
+
+
+struct load_freq_table {
+ u32 load;
+ u32 freq;
+ u32 supported_codecs;
+};
+
+struct reg_value_pair {
+ u32 reg;
+ u32 value;
+};
+
+struct reg_set {
+ struct reg_value_pair *reg_tbl;
+ int count;
+};
+
+struct addr_range {
+ u32 start;
+ u32 size;
+};
+
+struct addr_set {
+ struct addr_range *addr_tbl;
+ int count;
+};
+
+struct context_bank_info {
+ struct list_head list;
+ const char *name;
+ u32 buffer_type;
+ bool is_secure;
+ struct addr_range addr_range;
+ struct device *dev;
+ struct dma_iommu_mapping *mapping;
+ void *alloc_ctx;
+};
+
+struct buffer_usage_table {
+ u32 buffer_type;
+ u32 tz_usage;
+};
+
+struct buffer_usage_set {
+ struct buffer_usage_table *buffer_usage_tbl;
+ u32 count;
+};
+
+struct regulator_info {
+ struct regulator *regulator;
+ bool has_hw_power_collapse;
+ char *name;
+};
+
+struct regulator_set {
+ struct regulator_info *regulator_tbl;
+ u32 count;
+};
+
+struct clock_info {
+ const char *name;
+ struct clk *clk;
+ struct load_freq_table *load_freq_tbl;
+ u32 count; /* == has_scaling iff count != 0 */
+ bool has_gating;
+};
+
+struct clock_set {
+ struct clock_info *clock_tbl;
+ u32 count;
+};
+
+struct bus_info {
+ struct msm_bus_scale_pdata *pdata;
+ u32 priv;
+ u32 sessions_supported; /* bitmask */
+ bool passive;
+};
+
+struct bus_set {
+ struct bus_info *bus_tbl;
+ u32 count;
+};
+
+enum imem_type {
+ IMEM_NONE,
+ IMEM_OCMEM,
+ IMEM_VMEM,
+ IMEM_MAX,
+};
+
+struct msm_vidc_platform_resources {
+ phys_addr_t firmware_base;
+ phys_addr_t register_base;
+ uint32_t register_size;
+ uint32_t irq;
+ struct load_freq_table *load_freq_tbl;
+ uint32_t load_freq_tbl_size;
+ struct reg_set reg_set;
+ struct addr_set qdss_addr_set;
+ struct buffer_usage_set buffer_usage_set;
+ uint32_t imem_size;
+ enum imem_type imem_type;
+ uint32_t max_load;
+ struct platform_device *pdev;
+ struct regulator_set regulator_set;
+ struct clock_set clock_set;
+ struct bus_set bus_set;
+ bool use_non_secure_pil;
+ bool sw_power_collapsible;
+ bool sys_idle_indicator;
+ struct list_head context_banks;
+ bool early_fw_load;
+ bool thermal_mitigable;
+ const char *fw_name;
+ const char *hfi_version;
+};
+
+static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
+{
+ return !list_empty(&res->context_banks);
+}
+
+extern uint32_t msm_vidc_pwr_collapse_delay;
+
+#endif
+
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
new file mode 100644
index 000000000000..8f697c514911
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -0,0 +1,1230 @@
+/* Copyright (c) 2013-2015, 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/slab.h>
+#include <linux/iommu.h>
+//#include <linux/msm_iommu_domains.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+#include "q6_hfi.h"
+#include "vidc_hfi_api.h"
+
+
+#if defined(CONFIG_MSM_QDSP6_APR) || defined(CONFIG_MSM_QDSP6_APRV2)
+#include <linux/qdsp6v2/apr.h>
+
+static struct hal_device_data hal_ctxt;
+
+static int write_queue(void *info, u8 *packet)
+{
+ u32 packet_size_in_words, new_write_idx;
+ struct q6_iface_q_info *qinfo;
+ u32 empty_space, read_idx;
+ u32 *write_ptr;
+
+ if (!info || !packet) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ qinfo = (struct q6_iface_q_info *) info;
+
+ packet_size_in_words = (*(u32 *)packet) >> 2;
+
+ if (!packet_size_in_words) {
+ dprintk(VIDC_ERR, "Zero packet size\n");
+ return -ENODATA;
+ }
+
+ read_idx = qinfo->read_idx;
+
+ empty_space = (qinfo->write_idx >= read_idx) ?
+ (qinfo->q_size - (qinfo->write_idx - read_idx)) :
+ (read_idx - qinfo->write_idx);
+ if (empty_space <= packet_size_in_words) {
+ dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
+ empty_space, packet_size_in_words);
+ return -ENOTEMPTY;
+ }
+
+ new_write_idx = (qinfo->write_idx + packet_size_in_words);
+ write_ptr = (u32 *)(qinfo->buffer + (qinfo->write_idx << 2));
+ if (new_write_idx < qinfo->q_size) {
+ memcpy(write_ptr, packet, packet_size_in_words << 2);
+ } else {
+ new_write_idx -= qinfo->q_size;
+ memcpy(write_ptr, packet, (packet_size_in_words -
+ new_write_idx) << 2);
+ memcpy((void *)qinfo->buffer,
+ packet + ((packet_size_in_words - new_write_idx) << 2),
+ new_write_idx << 2);
+ }
+ qinfo->write_idx = new_write_idx;
+ return 0;
+}
+
+static int read_queue(void *info, u8 *packet)
+{
+ u32 packet_size_in_words, new_read_idx;
+ u32 *read_ptr;
+ struct q6_iface_q_info *qinfo;
+
+ if (!info || !packet) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ qinfo = (struct q6_iface_q_info *) info;
+
+ if (qinfo->read_idx == qinfo->write_idx)
+ return -EPERM;
+
+ read_ptr = (u32 *)(qinfo->buffer + (qinfo->read_idx << 2));
+ packet_size_in_words = (*read_ptr) >> 2;
+ if (!packet_size_in_words) {
+ dprintk(VIDC_ERR, "Zero packet size\n");
+ return -ENODATA;
+ }
+
+ new_read_idx = qinfo->read_idx + packet_size_in_words;
+ if (new_read_idx < qinfo->q_size) {
+ memcpy(packet, read_ptr,
+ packet_size_in_words << 2);
+ } else {
+ new_read_idx -= qinfo->q_size;
+ memcpy(packet, read_ptr,
+ (packet_size_in_words - new_read_idx) << 2);
+ memcpy(packet + ((packet_size_in_words -
+ new_read_idx) << 2),
+ (u8 *)qinfo->buffer,
+ new_read_idx << 2);
+ }
+
+ qinfo->read_idx = new_read_idx;
+ return 0;
+}
+
+static int q6_hfi_iface_eventq_write(struct q6_hfi_device *device, void *pkt)
+{
+ struct q6_iface_q_info *q_info;
+ int rc = 0;
+ unsigned long flags = 0;
+
+ if (!device || !pkt) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ q_info = &device->event_queue;
+ if (!q_info->buffer) {
+ dprintk(VIDC_ERR, "cannot write to shared Q\n");
+ rc = -ENODATA;
+ goto err_q_write;
+ }
+
+ spin_lock_irqsave(&q_info->lock, flags);
+ rc = write_queue(q_info, (u8 *)pkt);
+ if (rc)
+ dprintk(VIDC_ERR, "q6_hfi_iface_eventq_write: queue_full\n");
+
+ spin_unlock_irqrestore(&q_info->lock, flags);
+err_q_write:
+ return rc;
+}
+
+static int q6_hfi_iface_eventq_read(struct q6_hfi_device *device, void *pkt)
+{
+ int rc = 0;
+ struct q6_iface_q_info *q_info;
+ unsigned long flags = 0;
+
+ if (!device || !pkt) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ q_info = &device->event_queue;
+
+ if (!q_info->buffer) {
+ dprintk(VIDC_ERR, "cannot read from shared Q\n");
+ rc = -ENODATA;
+ goto read_error;
+ }
+
+ spin_lock_irqsave(&q_info->lock, flags);
+ rc = read_queue(q_info, (u8 *)pkt);
+ if (rc) {
+ dprintk(VIDC_INFO, "q6_hfi_iface_eventq_read:queue_empty\n");
+ rc = -ENODATA;
+ }
+ spin_unlock_irqrestore(&q_info->lock, flags);
+
+read_error:
+ return rc;
+}
+
+static void q6_hfi_core_work_handler(struct work_struct *work)
+{
+ int rc = 0;
+ struct q6_hfi_device *device = container_of(
+ work, struct q6_hfi_device, vidc_worker);
+ u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
+
+ /* need to consume all the messages from the firmware */
+ do {
+ rc = q6_hfi_iface_eventq_read(device, packet);
+ if (!rc)
+ hfi_process_msg_packet(device->callback,
+ device->device_id,
+ (struct vidc_hal_msg_pkt_hdr *) packet,
+ &device->sess_head, &device->session_lock);
+ } while (!rc);
+
+ if (rc != -ENODATA)
+ dprintk(VIDC_ERR, "Failed to read from event queue\n");
+}
+
+static int q6_hfi_init_resources(struct q6_hfi_device *device,
+ struct msm_vidc_platform_resources *res)
+{
+ if (!device || !res) {
+ dprintk(VIDC_ERR, "Invalid device or resources\n");
+ return -EINVAL;
+ }
+
+ device->res = res;
+ return 0;
+}
+
+static void *q6_hfi_add_device(u32 device_id,
+ hfi_cmd_response_callback callback)
+{
+ struct q6_hfi_device *hdevice = NULL;
+
+ if (!callback) {
+ dprintk(VIDC_ERR, "Invalid Paramters\n");
+ return NULL;
+ }
+
+ hdevice = (struct q6_hfi_device *)
+ kzalloc(sizeof(struct q6_hfi_device), GFP_KERNEL);
+ if (!hdevice) {
+ dprintk(VIDC_ERR, "failed to allocate new device\n");
+ goto err_alloc;
+ }
+
+ hdevice->device_id = device_id;
+ hdevice->callback = callback;
+
+ dprintk(VIDC_DBG, "q6_hfi_add_device device_id %d\n", device_id);
+
+ INIT_WORK(&hdevice->vidc_worker, q6_hfi_core_work_handler);
+ hdevice->vidc_workq = create_singlethread_workqueue(
+ "msm_vidc_workerq_q6");
+ if (!hdevice->vidc_workq) {
+ dprintk(VIDC_ERR, ": create workq failed\n");
+ goto error_createq;
+ }
+
+ if (!hal_ctxt.dev_count)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
+ list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+ hal_ctxt.dev_count++;
+
+ return (void *) hdevice;
+error_createq:
+ kfree(hdevice);
+err_alloc:
+ return NULL;
+}
+
+static void *q6_hfi_get_device(u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ struct q6_hfi_device *device;
+ int rc = 0;
+
+ if (!callback) {
+ dprintk(VIDC_ERR, "%s Invalid params: %p\n",
+ __func__, callback);
+ return NULL;
+ }
+
+ device = q6_hfi_add_device(device_id, &handle_cmd_response);
+ if (!device) {
+ dprintk(VIDC_ERR, "Failed to create HFI device\n");
+ return NULL;
+ }
+
+ rc = q6_hfi_init_resources(device, res);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+ goto err_fail_init_res;
+ }
+
+ device->pkt_ops = hfi_get_pkt_ops_handle(HFI_PACKETIZATION_LEGACY);
+ if (!device->pkt_ops) {
+ dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n");
+ goto err_fail_init_res;
+ }
+
+ return device;
+
+err_fail_init_res:
+ q6_hfi_delete_device(device);
+ return ERR_PTR(rc);
+}
+
+void q6_hfi_delete_device(void *device)
+{
+ struct q6_hfi_device *close, *tmp, *dev;
+
+ if (device) {
+ dev = (struct q6_hfi_device *) device;
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
+ if (close->device_id == dev->device_id) {
+ hal_ctxt.dev_count--;
+ list_del(&close->list);
+ destroy_workqueue(close->vidc_workq);
+ kfree(close);
+ break;
+ }
+ }
+
+ }
+}
+
+static inline void q6_hfi_add_apr_hdr(struct q6_hfi_device *dev,
+ struct apr_hdr *hdr, u32 pkt_size)
+{
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+
+ hdr->src_svc = ((struct apr_svc *)dev->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_VIDC;
+ hdr->src_port = 0;
+ hdr->dest_port = 0;
+ hdr->pkt_size = pkt_size;
+ hdr->token = 0;
+ hdr->opcode = VIDEO_HFI_CMD_ID;
+}
+
+static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
+{
+ struct q6_hfi_device *device = priv;
+ struct hfi_msg_event_notify_packet pkt = {0};
+ void *payload = NULL;
+ int rc = 0;
+
+ if (!data || !device) {
+ dprintk(VIDC_ERR, "%s - Invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ dprintk(VIDC_DBG, "%s opcode = %u payload size = %u\n", __func__,
+ data->opcode, data->payload_size);
+
+ if (data->opcode == RESET_EVENTS) {
+ dprintk(VIDC_ERR, "%s Received subsystem reset event: %d\n",
+ __func__, data->reset_event);
+ pkt.packet_type = HFI_MSG_EVENT_NOTIFY;
+ pkt.size = sizeof(pkt);
+ pkt.event_id = HFI_EVENT_SYS_ERROR;
+ pkt.event_data1 = data->opcode;
+ pkt.event_data2 = data->reset_event;
+ payload = &pkt;
+ } else if (data->payload_size > 0) {
+ payload = data->payload;
+ } else {
+ dprintk(VIDC_ERR, "%s - Invalid payload size\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = q6_hfi_iface_eventq_write(device, payload);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s failed to write to event queue\n",
+ __func__);
+ return rc;
+ }
+ queue_work(device->vidc_workq, &device->vidc_worker);
+ return 0;
+}
+
+static void q6_release_event_queue(struct q6_hfi_device *device)
+{
+ kfree(device->event_queue.buffer);
+ device->event_queue.buffer = NULL;
+ device->event_queue.q_size = 0;
+ device->event_queue.read_idx = 0;
+ device->event_queue.write_idx = 0;
+}
+
+static int q6_init_event_queue(struct q6_hfi_device *dev)
+{
+ struct q6_iface_q_info *iface_q;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "Invalid device\n");
+ return -EINVAL;
+ }
+
+ iface_q = &dev->event_queue;
+ iface_q->buffer = kzalloc(Q6_IFACEQ_QUEUE_SIZE, GFP_KERNEL);
+ if (!iface_q->buffer) {
+ dprintk(VIDC_ERR, "iface_q alloc failed\n");
+ q6_release_event_queue(dev);
+ return -ENOMEM;
+ } else {
+ iface_q->q_size = Q6_IFACEQ_QUEUE_SIZE / 4;
+ iface_q->read_idx = 0;
+ iface_q->write_idx = 0;
+ spin_lock_init(&iface_q->lock);
+ }
+ return 0;
+}
+
+static int q6_hfi_core_init(void *device)
+{
+ struct q6_apr_cmd_sys_init_packet apr;
+ int rc = 0;
+ struct q6_hfi_device *dev = device;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "%s: invalid argument\n", __func__);
+ return -ENODEV;
+ }
+
+ INIT_LIST_HEAD(&dev->sess_head);
+ mutex_init(&dev->session_lock);
+
+ if (!dev->event_queue.buffer) {
+ rc = q6_init_event_queue(dev);
+ if (rc) {
+ dprintk(VIDC_ERR, "q6_init_event_queue failed\n");
+ goto err_core_init;
+ }
+ } else {
+ dprintk(VIDC_ERR, "queue buffer exists\n");
+ rc = -EEXIST;
+ goto err_core_init;
+ }
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, sys_init, &apr.pkt, HFI_VIDEO_ARCH_OX);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to create sys init pkt\n");
+ goto err_core_init;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_core_init:
+ return rc;
+}
+
+static int q6_hfi_core_release(void *device)
+{
+ struct q6_hfi_device *dev = device;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "%s: invalid argument\n", __func__);
+ return -ENODEV;
+ }
+ q6_release_event_queue(dev);
+
+ dprintk(VIDC_DBG, "HAL exited\n");
+ return 0;
+}
+
+static void *q6_hfi_session_init(void *device, void *session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type)
+{
+ struct q6_apr_cmd_sys_session_init_packet apr;
+ struct hal_session *new_session;
+ struct q6_hfi_device *dev = device;
+ int rc = 0;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "%s: invalid argument\n", __func__);
+ return NULL;
+ }
+
+ new_session = (struct hal_session *)
+ kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+ if (!new_session) {
+ dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+ return NULL;
+ }
+ new_session->session_id = session_id;
+ new_session->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER);
+ new_session->device = dev;
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ if (call_hfi_pkt_op(dev, session_init,
+ &apr.pkt, new_session, session_type, codec_type)) {
+ dprintk(VIDC_ERR, "session_init: failed to create packet\n");
+ goto err_session_init;
+ }
+ /*
+ * Add session id to the list entry and then send the apr pkt.
+ * This will avoid scenarios where apr_send_pkt is taking more
+ * time and Q6 is returning an ack even before the session id
+ * gets added to the session list.
+ */
+ mutex_lock(&dev->session_lock);
+ list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ /* Delete the session id as the send pkt is not successful */
+ mutex_lock(&dev->session_lock);
+ list_del(&new_session->list);
+ mutex_unlock(&dev->session_lock);
+ rc = -EBADE;
+ goto err_session_init;
+ }
+
+ return new_session;
+
+err_session_init:
+ kfree(new_session);
+ return NULL;
+}
+
+static int q6_hal_send_session_cmd(void *sess,
+ int pkt_type)
+{
+ struct q6_apr_session_cmd_pkt apr;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "%s: invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_cmd, &apr.pkt, pkt_type, session);
+ if (rc) {
+ dprintk(VIDC_ERR, "send session cmd: create pkt failed\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_end(void *session)
+{
+ return q6_hal_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_END);
+}
+
+static int q6_hfi_session_abort(void *session)
+{
+ return q6_hal_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_ABORT);
+}
+
+static int q6_hfi_session_clean(void *session)
+{
+ struct hal_session *sess_close;
+ if (!session) {
+ dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+ return -EINVAL;
+ }
+ sess_close = session;
+ dprintk(VIDC_DBG, "deleted the session: %p\n",
+ sess_close->session_id);
+ mutex_lock(&((struct q6_hfi_device *)
+ sess_close->device)->session_lock);
+ list_del(&sess_close->list);
+ mutex_unlock(&((struct q6_hfi_device *)
+ sess_close->device)->session_lock);
+ kfree(sess_close);
+ return 0;
+}
+
+static int q6_hfi_session_set_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct q6_apr_cmd_session_set_buffers_packet *apr;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !buffer_info || !session->device) {
+ dprintk(VIDC_ERR, "%s: invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+ apr = (struct q6_apr_cmd_session_set_buffers_packet *)packet;
+
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
+
+
+ rc = call_hfi_pkt_op(dev, session_set_buffers,
+ &apr->pkt, session, buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "set buffers: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type);
+ rc = apr_send_pkt(dev->apr, (uint32_t *)apr);
+ if (rc != apr->hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_release_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct q6_apr_cmd_session_release_buffer_packet *apr;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !buffer_info || !session->device) {
+ dprintk(VIDC_ERR, "%s: invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ dev = session->device;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+
+ apr = (struct q6_apr_cmd_session_release_buffer_packet *) packet;
+
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
+
+ rc = call_hfi_pkt_op(dev, session_release_buffers,
+ &apr->pkt, session, buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "release buffers: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type);
+ rc = apr_send_pkt(dev->apr, (uint32_t *)apr);
+
+ if (rc != apr->hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_load_res(void *sess)
+{
+ return q6_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_LOAD_RESOURCES);
+}
+
+static int q6_hfi_session_release_res(void *sess)
+{
+ return q6_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_RELEASE_RESOURCES);
+}
+
+static int q6_hfi_session_start(void *sess)
+{
+ return q6_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_START);
+}
+
+static int q6_hfi_session_stop(void *sess)
+{
+ return q6_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_STOP);
+}
+
+static int q6_hfi_session_etb(void *sess,
+ struct vidc_frame_data *input_frame)
+{
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !input_frame || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ dev = session->device;
+
+ if (session->is_decoder) {
+ struct q6_apr_cmd_session_empty_buffer_compressed_packet apr;
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_etb_decoder,
+ &apr.pkt, session, input_frame);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session etb decoder: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+ dprintk(VIDC_DBG, "Q DECODER INPUT BUFFER\n");
+ dprintk(VIDC_DBG, "addr = %pa ts = %lld\n",
+ &input_frame->device_addr, input_frame->timestamp);
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+ } else {
+ struct
+ q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet apr;
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_etb_encoder,
+ &apr.pkt, session, input_frame);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session etb encoder: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+ dprintk(VIDC_DBG, "Q ENCODER INPUT BUFFER\n");
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+ }
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_ftb(void *sess,
+ struct vidc_frame_data *output_frame)
+{
+ struct q6_apr_cmd_session_fill_buffer_packet apr;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !output_frame || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_ftb,
+ &apr.pkt, session, output_frame);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ dprintk(VIDC_INFO, "Q OUTPUT BUFFER\n");
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_parse_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct q6_apr_cmd_session_parse_sequence_header_packet *apr;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !seq_hdr || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ apr = (struct q6_apr_cmd_session_parse_sequence_header_packet *) packet;
+
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
+
+ rc = call_hfi_pkt_op(dev, session_parse_seq_header,
+ &apr->pkt, session, seq_hdr);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session parse seq hdr: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)apr);
+ if (rc != apr->hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_get_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct q6_apr_cmd_session_get_sequence_header_packet *apr;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !seq_hdr || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ apr = (struct q6_apr_cmd_session_get_sequence_header_packet *) packet;
+
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
+
+ rc = call_hfi_pkt_op(dev, session_get_seq_hdr,
+ &apr->pkt, session, seq_hdr);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session get seqhdr: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)apr);
+ if (rc != apr->hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_get_buf_req(void *sess)
+{
+ struct q6_apr_cmd_session_get_property_packet apr;
+ int rc = 0;
+ struct hal_session *session = sess;
+
+ struct q6_hfi_device *dev;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_get_buf_req,
+ &apr.pkt, session);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session get bufreq: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_flush(void *sess, enum hal_flush flush_mode)
+{
+ struct q6_apr_cmd_session_flush_packet apr;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
+
+ rc = call_hfi_pkt_op(dev, session_flush,
+ &apr.pkt, session, flush_mode);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session flush: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
+ if (rc != apr.hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_set_property(void *sess,
+ enum hal_property ptype, void *pdata)
+{
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ struct q6_apr_cmd_session_set_property_packet *apr =
+ (struct q6_apr_cmd_session_set_property_packet *) &packet;
+ struct hal_session *session = sess;
+ int rc = 0;
+ struct q6_hfi_device *dev;
+
+ if (!session || !pdata || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ if (ptype == HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER) {
+ dprintk(VIDC_WARN, "Smoothstreaming is not supported\n");
+ return -ENOTSUPP;
+ }
+
+ dev = session->device;
+ dprintk(VIDC_DBG, "in set_prop,with prop id: %#x\n", ptype);
+
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
+
+ rc = call_hfi_pkt_op(dev, session_set_property,
+ &apr->pkt, session, ptype, pdata);
+ if (rc) {
+ dprintk(VIDC_ERR, "set property: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ rc = apr_send_pkt(dev->apr, (uint32_t *)apr);
+ if (rc != apr->hdr.pkt_size) {
+ dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d\n",
+ __func__, rc);
+ rc = -EBADE;
+ } else
+ rc = 0;
+
+err_create_pkt:
+ return rc;
+}
+
+static int q6_hfi_session_get_property(void *sess,
+ enum hal_property ptype)
+{
+ struct hal_session *session = sess;
+ struct q6_hfi_device *dev;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ dev = session->device;
+
+ dprintk(VIDC_DBG, "IN func: , with property id: %d\n", ptype);
+
+ switch (ptype) {
+ case HAL_CONFIG_FRAME_RATE:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+ break;
+ case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+ break;
+ case HAL_PARAM_FRAME_SIZE:
+ break;
+ case HAL_CONFIG_REALTIME:
+ break;
+ case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+ break;
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ break;
+ case HAL_PARAM_VDEC_OUTPUT_ORDER:
+ break;
+ case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+ break;
+ case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+ break;
+ case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+ break;
+ case HAL_PARAM_VDEC_MULTI_STREAM:
+ break;
+ case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+ break;
+ case HAL_PARAM_DIVX_FORMAT:
+ break;
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+ break;
+ case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+ break;
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP:
+ break;
+ case HAL_CONFIG_VENC_REQUEST_IFRAME:
+ break;
+ case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+ break;
+ case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+ break;
+ case HAL_CONFIG_VENC_TARGET_BITRATE:
+ break;
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ break;
+ case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+ break;
+ case HAL_PARAM_VENC_RATE_CONTROL:
+ break;
+ case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+ break;
+ case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+ break;
+ case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+ break;
+ case HAL_PARAM_VENC_SESSION_QP:
+ break;
+ case HAL_CONFIG_VENC_INTRA_PERIOD:
+ break;
+ case HAL_CONFIG_VENC_IDR_PERIOD:
+ break;
+ case HAL_CONFIG_VPE_OPERATIONS:
+ break;
+ case HAL_PARAM_VENC_INTRA_REFRESH:
+ break;
+ case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+ break;
+ case HAL_CONFIG_VPE_DEINTERLACE:
+ break;
+ case HAL_SYS_DEBUG_CONFIG:
+ break;
+ /*FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET*/
+ case HAL_CONFIG_BUFFER_REQUIREMENTS:
+ case HAL_CONFIG_PRIORITY:
+ case HAL_CONFIG_BATCH_INFO:
+ case HAL_PARAM_METADATA_PASS_THROUGH:
+ case HAL_SYS_IDLE_INDICATOR:
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+ case HAL_PARAM_CHROMA_SITE:
+ case HAL_PARAM_PROPERTIES_SUPPORTED:
+ case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+ case HAL_PARAM_CAPABILITY_SUPPORTED:
+ case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ case HAL_PARAM_MULTI_VIEW_FORMAT:
+ case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ case HAL_PARAM_CODEC_SUPPORTED:
+ case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+ case HAL_PARAM_VDEC_MB_QUANTIZATION:
+ case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+ case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+
+ case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+ case HAL_CONFIG_VDEC_MULTI_STREAM:
+ case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+ case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+ case HAL_PARAM_VENC_LOW_LATENCY:
+ default:
+ dprintk(VIDC_INFO, "DEFAULT: Calling %#x\n", ptype);
+ break;
+ }
+ return 0;
+}
+
+static int q6_hfi_load_fw(void *dev)
+{
+ int rc = 0;
+ struct q6_hfi_device *device = dev;
+
+ if (!device)
+ return -EINVAL;
+
+ trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc adsp_fw load start");
+ if (!device->resources.fw.cookie)
+ device->resources.fw.cookie = subsystem_get("adsp");
+
+ if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
+ dprintk(VIDC_ERR, "Failed to download firmware\n");
+ rc = -ENOMEM;
+ goto fail_subsystem_get;
+ }
+
+ /*Set Q6 to loaded state*/
+ apr_set_q6_state(APR_SUBSYS_LOADED);
+
+ device->apr = apr_register("ADSP", "VIDC",
+ (apr_fn)q6_hfi_apr_callback,
+ 0xFFFFFFFF,
+ device);
+
+ if (device->apr == NULL) {
+ dprintk(VIDC_ERR, "Failed to register with QDSP6\n");
+ rc = -EINVAL;
+ goto fail_apr_register;
+ }
+ trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc adsp_fw load end");
+ return rc;
+fail_apr_register:
+ subsystem_put(device->resources.fw.cookie);
+ device->resources.fw.cookie = NULL;
+fail_subsystem_get:
+ trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc adsp_fw load end");
+ return rc;
+}
+
+static void q6_hfi_unload_fw(void *hfi_device_data)
+{
+ struct q6_hfi_device *device = hfi_device_data;
+
+ if (!device)
+ return;
+
+ if (device->resources.fw.cookie) {
+ subsystem_put(device->resources.fw.cookie);
+ device->resources.fw.cookie = NULL;
+ }
+
+ if (device->apr) {
+ if (apr_deregister(device->apr))
+ dprintk(VIDC_ERR, "Failed to deregister APR\n");
+ device->apr = NULL;
+ }
+}
+
+static int q6_hfi_get_stride_scanline(int color_fmt,
+ int width, int height, int *stride, int *scanlines) {
+ *stride = VENUS_Y_STRIDE(color_fmt, width);
+ *scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+ return 0;
+}
+
+static void q6_init_hfi_callbacks(struct hfi_device *hdev)
+{
+ hdev->core_init = q6_hfi_core_init;
+ hdev->core_release = q6_hfi_core_release;
+ hdev->session_init = q6_hfi_session_init;
+ hdev->session_end = q6_hfi_session_end;
+ hdev->session_abort = q6_hfi_session_abort;
+ hdev->session_clean = q6_hfi_session_clean;
+ hdev->session_set_buffers = q6_hfi_session_set_buffers;
+ hdev->session_release_buffers = q6_hfi_session_release_buffers;
+ hdev->session_load_res = q6_hfi_session_load_res;
+ hdev->session_release_res = q6_hfi_session_release_res;
+ hdev->session_start = q6_hfi_session_start;
+ hdev->session_stop = q6_hfi_session_stop;
+ hdev->session_etb = q6_hfi_session_etb;
+ hdev->session_ftb = q6_hfi_session_ftb;
+ hdev->session_parse_seq_hdr = q6_hfi_session_parse_seq_hdr;
+ hdev->session_get_seq_hdr = q6_hfi_session_get_seq_hdr;
+ hdev->session_get_buf_req = q6_hfi_session_get_buf_req;
+ hdev->session_flush = q6_hfi_session_flush;
+ hdev->session_set_property = q6_hfi_session_set_property;
+ hdev->session_get_property = q6_hfi_session_get_property;
+ hdev->load_fw = q6_hfi_load_fw;
+ hdev->unload_fw = q6_hfi_unload_fw;
+ hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
+}
+
+
+int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ int rc = 0;
+
+ if (!hdev || !res || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p %p\n",
+ hdev, res, callback);
+ rc = -EINVAL;
+ goto err_hfi_init;
+ }
+ hdev->hfi_device_data = q6_hfi_get_device(device_id, res, callback);
+
+ if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+ rc = PTR_ERR(hdev->hfi_device_data) ?: -EINVAL;
+ goto err_hfi_init;
+ }
+
+ q6_init_hfi_callbacks(hdev);
+
+err_hfi_init:
+ return rc;
+}
+
+#else
+int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ return -ENODEV;
+}
+
+void q6_hfi_delete_device(void *device)
+{
+ /* Nothing to do! */
+}
+#endif
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
new file mode 100644
index 000000000000..7cee75a7b553
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -0,0 +1,133 @@
+/* Copyright (c) 2013-2014, 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.
+ *
+ */
+#ifndef __Q6_HFI_H__
+#define __Q6_HFI_H__
+
+#include "vidc_hfi.h"
+
+#if defined(CONFIG_MSM_QDSP6_APR) || defined(CONFIG_MSM_QDSP6_APRV2)
+#include <linux/qdsp6v2/apr.h>
+#include "vidc_hfi_helper.h"
+#include "msm_vidc_resources.h"
+
+#define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
+
+/* client to Q6 communication path : forward path */
+#define VIDEO_HFI_CMD_ID 0x00012ECC
+
+/* Q6 to client ACK msg: reverse path*/
+#define VIDEO_HFI_MSG_ID 0x00012ECD
+
+/* Q6 to client event notifications */
+#define VIDEO_HFI_EVT_ID 0x00012ECE
+
+struct q6_resources {
+ struct msm_vidc_fw fw;
+};
+
+struct q6_iface_q_info {
+ spinlock_t lock;
+ u32 q_size;
+ u32 read_idx;
+ u32 write_idx;
+ u8 *buffer;
+};
+
+struct q6_hfi_device {
+ struct list_head list;
+ struct list_head sess_head;
+ struct q6_iface_q_info event_queue;
+ struct workqueue_struct *vidc_workq;
+ struct work_struct vidc_worker;
+ u32 device_id;
+ msm_vidc_callback callback;
+ struct q6_resources resources;
+ struct msm_vidc_platform_resources *res;
+ void *apr;
+ struct mutex session_lock;
+ struct hfi_packetization_ops *pkt_ops;
+};
+
+struct q6_apr_cmd_sys_init_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_sys_init_packet pkt;
+};
+
+struct q6_apr_cmd_sys_session_init_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_sys_session_init_packet pkt;
+};
+
+struct q6_apr_session_cmd_pkt {
+ struct apr_hdr hdr;
+ struct vidc_hal_session_cmd_pkt pkt;
+};
+
+struct q6_apr_cmd_session_set_buffers_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_set_buffers_packet pkt;
+};
+
+struct q6_apr_cmd_session_release_buffer_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_release_buffer_packet pkt;
+};
+
+struct q6_apr_cmd_session_empty_buffer_compressed_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
+};
+
+struct q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet pkt;
+};
+
+struct q6_apr_cmd_session_fill_buffer_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_fill_buffer_packet pkt;
+};
+
+struct q6_apr_cmd_session_parse_sequence_header_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_parse_sequence_header_packet pkt;
+};
+
+struct q6_apr_cmd_session_get_sequence_header_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_get_sequence_header_packet pkt;
+};
+
+struct q6_apr_cmd_session_get_property_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_get_property_packet pkt;
+};
+
+struct q6_apr_cmd_session_flush_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_flush_packet pkt;
+};
+
+struct q6_apr_cmd_session_set_property_packet {
+ struct apr_hdr hdr;
+ struct hfi_cmd_session_set_property_packet pkt;
+};
+
+#endif /* APR */
+int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback);
+
+void q6_hfi_delete_device(void *device);
+
+#endif /*#ifndef __Q6_HFI_H__ */
diff --git a/drivers/media/platform/msm/vidc/venus_boot.c b/drivers/media/platform/msm/vidc/venus_boot.c
new file mode 100644
index 000000000000..63ef98cf2b9a
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/venus_boot.c
@@ -0,0 +1,520 @@
+/* Copyright (c) 2014-2015, 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.
+ */
+
+#define VIDC_DBG_LABEL "venus_boot"
+
+//#include <asm/dma-iommu.h>
+#include <asm/page.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+//#include <linux/msm_iommu_domains.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+//#include <linux/qcom_iommu.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_io.h"
+#include "venus_boot.h"
+
+/* VENUS WRAPPER registers */
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1018)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x101C)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1024)
+
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1024)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x1028)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2 \
+ (VIDC_WRAPPER_BASE_OFFS + 0x102C)
+
+#define VENUS_WRAPPER_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x3000)
+
+/* VENUS VBIF registers */
+#define VENUS_VBIF_CLKON_FORCE_ON BIT(0)
+
+#define VENUS_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0x1000)
+#define VENUS_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0x1004)
+#define VENUS_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0x1008)
+#define VENUS_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0x1010)
+#define VENUS_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0x1018)
+
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
+#define VENUS_REGION_SIZE 0x00500000
+
+static struct {
+ struct msm_vidc_platform_resources *resources;
+ struct regulator *gdsc;
+ const char *reg_name;
+ void __iomem *reg_base;
+ struct device *iommu_ctx_bank_dev;
+ struct dma_iommu_mapping *mapping;
+ dma_addr_t fw_iova;
+ bool is_booted;
+ bool hw_ver_checked;
+ u32 fw_sz;
+ u32 hw_ver_major;
+ u32 hw_ver_minor;
+ void *venus_notif_hdle;
+} *venus_data = NULL;
+
+/* Get venus clocks and set rates for rate-settable clocks */
+static int venus_clock_setup(void)
+{
+ int i, rc = 0;
+ unsigned long rate;
+ struct msm_vidc_platform_resources *res = venus_data->resources;
+ struct clock_info *cl;
+
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ /* Make sure rate-settable clocks' rates are set */
+ if (!clk_get_rate(cl->clk) && cl->count) {
+ rate = clk_round_rate(cl->clk, 0);
+ rc = clk_set_rate(cl->clk, rate);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set clock rate %lu %s: %d\n",
+ rate, cl->name, rc);
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int venus_clock_prepare_enable(void)
+{
+ int i, rc = 0;
+ struct msm_vidc_platform_resources *res = venus_data->resources;
+ struct clock_info *cl;
+
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ rc = clk_prepare_enable(cl->clk);
+ if (rc) {
+ dprintk(VIDC_ERR, "failed to enable %s\n", cl->name);
+ for (i--; i >= 0; i--) {
+ cl = &res->clock_set.clock_tbl[i];
+ clk_disable_unprepare(cl->clk);
+ }
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static void venus_clock_disable_unprepare(void)
+{
+ int i;
+ struct msm_vidc_platform_resources *res = venus_data->resources;
+ struct clock_info *cl;
+
+ for (i = 0; i < res->clock_set.count; i++) {
+ cl = &res->clock_set.clock_tbl[i];
+ clk_disable_unprepare(cl->clk);
+ }
+}
+
+#if 0
+static int venus_setup_cb(struct device *dev,
+ u32 size)
+{
+ int order = 0;
+ dma_addr_t va_start = 0x0;
+ size_t va_size = size;
+
+ venus_data->mapping = arm_iommu_create_mapping(
+ &platform_bus_type, va_start, va_size, order);
+ if (IS_ERR_OR_NULL(venus_data->mapping)) {
+ dprintk(VIDC_ERR, "%s: failed to create mapping for %s\n",
+ __func__, dev_name(dev));
+ return -ENODEV;
+ }
+ dprintk(VIDC_DBG,
+ "%s Attached device %p and created mapping %p for %s\n",
+ __func__, dev, venus_data->mapping, dev_name(dev));
+ return 0;
+}
+#endif
+
+static int pil_venus_mem_setup(size_t size)
+{
+ int rc = 0;
+
+ if (!venus_data->mapping) {
+ size = round_up(size, SZ_4K);
+#if 0
+ rc = venus_setup_cb(venus_data->iommu_ctx_bank_dev, size);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to setup context bank for venus : %s\n",
+ __func__,
+ dev_name(venus_data->iommu_ctx_bank_dev));
+ return rc;
+ }
+#endif
+ venus_data->fw_sz = size;
+ }
+
+ return rc;
+}
+
+static int pil_venus_auth_and_reset(void)
+{
+ int rc;
+
+ /* Need to enable this for new SMMU to set the device attribute */
+ bool disable_htw = true;
+ phys_addr_t fw_bias = venus_data->resources->firmware_base;
+ void __iomem *reg_base = venus_data->reg_base;
+ u32 ver;
+ bool iommu_present = is_iommu_present(venus_data->resources);
+ struct device *dev = venus_data->iommu_ctx_bank_dev;
+
+ if (!fw_bias) {
+ dprintk(VIDC_ERR, "FW bias is not valid\n");
+ return -EINVAL;
+ }
+ venus_data->fw_iova = (dma_addr_t)NULL;
+ /* Get Venus version number */
+ if (!venus_data->hw_ver_checked) {
+ ver = readl_relaxed(reg_base + VIDC_WRAPPER_HW_VERSION);
+ venus_data->hw_ver_minor = (ver & 0x0FFF0000) >> 16;
+ venus_data->hw_ver_major = (ver & 0xF0000000) >> 28;
+ venus_data->hw_ver_checked = 1;
+ }
+
+ if (iommu_present) {
+ u32 cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr;
+ /* Get the cpa and fw start/end addr based on Venus version */
+ if (venus_data->hw_ver_major == 0x1 &&
+ venus_data->hw_ver_minor <= 1) {
+ cpa_start_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1;
+ cpa_end_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1;
+ fw_start_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1;
+ fw_end_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1;
+ } else {
+ cpa_start_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2;
+ cpa_end_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2;
+ fw_start_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2;
+ fw_end_addr =
+ VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2;
+ }
+
+ /* Program CPA start and end address */
+ writel_relaxed(0, reg_base + cpa_start_addr);
+ writel_relaxed(venus_data->fw_sz, reg_base + cpa_end_addr);
+
+ /* Program FW start and end address */
+ writel_relaxed(0, reg_base + fw_start_addr);
+ writel_relaxed(venus_data->fw_sz, reg_base + fw_end_addr);
+ } else {
+ rc = regulator_enable(venus_data->gdsc);
+ if (rc) {
+ dprintk(VIDC_ERR, "GDSC enable failed\n");
+ goto err;
+ }
+
+ rc = venus_clock_prepare_enable();
+ if (rc) {
+ dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+ regulator_disable(venus_data->gdsc);
+ goto err;
+ }
+
+ writel_relaxed(0, reg_base + VENUS_VBIF_AT_OLD_BASE);
+ writel_relaxed(VENUS_REGION_SIZE,
+ reg_base + VENUS_VBIF_AT_OLD_HIGH);
+ writel_relaxed(fw_bias, reg_base + VENUS_VBIF_AT_NEW_BASE);
+ writel_relaxed(fw_bias + VENUS_REGION_SIZE,
+ reg_base + VENUS_VBIF_AT_NEW_HIGH);
+ writel_relaxed(0x7F007F, reg_base + VENUS_VBIF_ADDR_TRANS_EN);
+ venus_clock_disable_unprepare();
+ regulator_disable(venus_data->gdsc);
+ }
+ /* Make sure all register writes are committed. */
+ mb();
+
+ /*
+ * Need to wait 10 cycles of internal clocks before bringing ARM9
+ * out of reset.
+ */
+ udelay(1);
+
+ if (iommu_present) {
+ phys_addr_t temp, pa = fw_bias;
+
+#if 0
+ rc = arm_iommu_attach_device(dev, venus_data->mapping);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to attach iommu for %s : %d\n",
+ dev_name(dev), rc);
+ goto release_mapping;
+ }
+
+ /* Enable this for new SMMU to set the device attribute */
+ if (iommu_domain_set_attr(venus_data->mapping->domain,
+ DOMAIN_ATTR_COHERENT_HTW_DISABLE,
+ &disable_htw)) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to disable COHERENT_HTW: %s\n",
+ __func__, dev_name(dev));
+ goto err_iommu_map;
+ }
+
+ dprintk(VIDC_DBG, "Attached and created mapping for %s\n",
+ dev_name(dev));
+
+ /* Map virtual addr space 0 - fw_sz to fw phys addr space */
+ rc = iommu_map(venus_data->mapping->domain,
+ venus_data->fw_iova, pa, venus_data->fw_sz,
+ IOMMU_READ|IOMMU_WRITE|IOMMU_NOEXEC|IOMMU_PRIV);
+ temp = iommu_iova_to_phys(venus_data->mapping->domain,
+ venus_data->fw_iova);
+
+ if (temp != pa) {
+ dprintk(VIDC_ERR,
+ "%s : iova_to_phys didn't match what we mapped! (mapped: %p, got: %p)\n",
+ dev_name(dev), &pa, &temp);
+ } else {
+ dprintk(VIDC_DBG,
+ "%s - Successfully mapped and performed test translation!\n",
+ dev_name(dev));
+ }
+
+ if (rc || (venus_data->fw_iova != 0)) {
+ dprintk(VIDC_ERR, "%s - Failed to setup IOMMU\n",
+ dev_name(dev));
+ goto err_iommu_map;
+ }
+#endif
+ }
+ /* Bring Arm9 out of reset */
+ writel_relaxed(0, reg_base + VENUS_WRAPPER_SW_RESET);
+
+ venus_data->is_booted = 1;
+ return 0;
+
+#if 0
+err_iommu_map:
+ if (iommu_present)
+ arm_iommu_detach_device(dev);
+release_mapping:
+ if (iommu_present)
+ arm_iommu_release_mapping(venus_data->mapping);
+#endif
+err:
+ return rc;
+}
+
+static int pil_venus_shutdown(void)
+{
+ void __iomem *reg_base = venus_data->reg_base;
+ u32 reg;
+ int rc;
+
+ if (!venus_data->is_booted)
+ return 0;
+
+ /* Assert the reset to ARM9 */
+ reg = readl_relaxed(reg_base + VENUS_WRAPPER_SW_RESET);
+ reg |= BIT(4);
+ writel_relaxed(reg, reg_base + VENUS_WRAPPER_SW_RESET);
+
+ /* Make sure reset is asserted before the mapping is removed */
+ mb();
+
+ if (is_iommu_present(venus_data->resources)) {
+#if 0
+ iommu_unmap(venus_data->mapping->domain, venus_data->fw_iova,
+ venus_data->fw_sz);
+ arm_iommu_detach_device(venus_data->iommu_ctx_bank_dev);
+#endif
+ }
+ /*
+ * Force the VBIF clk to be on to avoid AXI bridge halt ack failure
+ * for certain Venus version.
+ */
+ if (venus_data->hw_ver_major == 0x1 &&
+ (venus_data->hw_ver_minor == 0x2 ||
+ venus_data->hw_ver_minor == 0x3)) {
+ reg = readl_relaxed(reg_base + VIDC_VENUS_VBIF_CLK_ON);
+ reg |= VENUS_VBIF_CLKON_FORCE_ON;
+ writel_relaxed(reg, reg_base + VIDC_VENUS_VBIF_CLK_ON);
+ }
+
+ /* Halt AXI and AXI OCMEM VBIF Access */
+ reg = readl_relaxed(reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+ reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+ writel_relaxed(reg, reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout(reg_base + VENUS_VBIF_AXI_HALT_CTRL1,
+ reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dprintk(VIDC_ERR, "Port halt timeout\n");
+
+ venus_data->is_booted = 0;
+
+ return 0;
+}
+
+static int venus_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ struct notif_data *data = (struct notif_data *)ss_handle;
+ static bool venus_data_set;
+ int ret;
+
+ if (!data->no_auth)
+ return NOTIFY_DONE;
+
+ if (!venus_data_set) {
+ ret = venus_clock_setup();
+ if (ret)
+ return ret;
+
+ ret = of_property_read_string(data->pdev->dev.of_node,
+ "qcom,proxy-reg-names", &venus_data->reg_name);
+ if (ret)
+ return ret;
+
+ venus_data->gdsc = devm_regulator_get(
+ &data->pdev->dev, venus_data->reg_name);
+ if (IS_ERR(venus_data->gdsc)) {
+ dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+ return -ENODEV;
+ }
+
+ venus_data_set = true;
+ }
+
+ if (code != SUBSYS_AFTER_POWERUP && code != SUBSYS_AFTER_SHUTDOWN)
+ return NOTIFY_DONE;
+
+ ret = regulator_enable(venus_data->gdsc);
+ if (ret) {
+ dprintk(VIDC_ERR, "GDSC enable failed\n");
+ return ret;
+ }
+
+ ret = venus_clock_prepare_enable();
+ if (ret) {
+ dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+ goto err_clks;
+ }
+
+ if (code == SUBSYS_AFTER_POWERUP) {
+ if (is_iommu_present(venus_data->resources))
+ pil_venus_mem_setup(VENUS_REGION_SIZE);
+ pil_venus_auth_and_reset();
+ } else if (code == SUBSYS_AFTER_SHUTDOWN)
+ pil_venus_shutdown();
+
+ venus_clock_disable_unprepare();
+ regulator_disable(venus_data->gdsc);
+
+ return NOTIFY_DONE;
+err_clks:
+ regulator_disable(venus_data->gdsc);
+ return ret;
+}
+
+static struct notifier_block venus_notifier = {
+ .notifier_call = venus_notifier_cb,
+};
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+ struct context_bank_info *cb)
+{
+ int rc = 0;
+
+ if (!res || !cb) {
+ dprintk(VIDC_ERR, "Invalid platform resource handle\n");
+ return -EINVAL;
+ }
+ venus_data = kzalloc(sizeof(*venus_data), GFP_KERNEL);
+ if (!venus_data)
+ return -ENOMEM;
+
+ venus_data->resources = res;
+ venus_data->iommu_ctx_bank_dev = cb->dev;
+ if (!venus_data->iommu_ctx_bank_dev) {
+ dprintk(VIDC_ERR, "Invalid venus context bank device\n");
+ return -ENODEV;
+ }
+ venus_data->reg_base = ioremap_nocache(res->register_base,
+ (unsigned long)res->register_size);
+ if (!venus_data->reg_base) {
+ dprintk(VIDC_ERR,
+ "could not map reg addr %pa of size %d\n",
+ &res->register_base, res->register_size);
+ rc = -ENOMEM;
+ goto err_ioremap_fail;
+ }
+ venus_data->venus_notif_hdle = subsys_notif_register_notifier("venus",
+ &venus_notifier);
+ if (IS_ERR(venus_data->venus_notif_hdle)) {
+ dprintk(VIDC_ERR, "register event notification failed\n");
+ rc = PTR_ERR(venus_data->venus_notif_hdle);
+ goto err_subsys_notif;
+ }
+
+ return rc;
+
+err_subsys_notif:
+err_ioremap_fail:
+ kfree(venus_data);
+ return rc;
+}
+
+void venus_boot_deinit(void)
+{
+ venus_data->resources = NULL;
+ subsys_notif_unregister_notifier(venus_data->venus_notif_hdle,
+ &venus_notifier);
+ kfree(venus_data);
+}
diff --git a/drivers/media/platform/msm/vidc/venus_boot.h b/drivers/media/platform/msm/vidc/venus_boot.h
new file mode 100644
index 000000000000..cbcfab7107cf
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/venus_boot.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2014, 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.
+ *
+ */
+
+#ifndef __VENUS_BOOT_H__
+#define __VENUS_BOOT_H__
+#include "msm_vidc_resources.h"
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+ struct context_bank_info *cb);
+void venus_boot_deinit(void);
+
+#endif /* __VENUS_BOOT_H__ */
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
new file mode 100644
index 000000000000..e997c082af65
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -0,0 +1,4331 @@
+/* Copyright (c) 2012-2015, 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 <asm/dma-iommu.h>
+#include <asm/memory.h>
+//#include <linux/coresight-stm.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+//#include <linux/qcom_iommu.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/qcom_scm.h>
+#include <soc/qcom/smem.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+#include "venus_hfi.h"
+#include "vidc_hfi_io.h"
+
+#define FIRMWARE_SIZE 0X00A00000
+#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
+#define QDSS_IOVA_START 0x80001000
+
+static struct hal_device_data hal_ctxt;
+
+#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
+struct tzbsp_memprot {
+ u32 cp_start;
+ u32 cp_size;
+ u32 cp_nonpixel_start;
+ u32 cp_nonpixel_size;
+};
+
+struct tzbsp_resp {
+ int ret;
+};
+
+#define TZBSP_VIDEO_SET_STATE 0xa
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
+enum tzbsp_video_state {
+ TZBSP_VIDEO_STATE_SUSPEND = 0,
+ TZBSP_VIDEO_STATE_RESUME
+};
+
+struct tzbsp_video_set_state_req {
+ u32 state; /*shoud be tzbsp_video_state enum value*/
+ u32 spare; /*reserved for future, should be zero*/
+};
+
+static void venus_hfi_pm_hndlr(struct work_struct *work);
+static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);
+static int venus_hfi_power_enable(void *dev);
+static inline int venus_hfi_power_on(
+ struct venus_hfi_device *device);
+static int venus_hfi_disable_regulators(struct venus_hfi_device *device);
+static int venus_hfi_enable_regulators(struct venus_hfi_device *device);
+static inline int venus_hfi_prepare_enable_clks(
+ struct venus_hfi_device *device);
+static inline void venus_hfi_disable_unprepare_clks(
+ struct venus_hfi_device *device);
+static void venus_hfi_flush_debug_queue(
+ struct venus_hfi_device *device, u8 *packet);
+static int venus_hfi_initialize_packetization(struct venus_hfi_device *device);
+
+static inline void venus_hfi_set_state(struct venus_hfi_device *device,
+ enum venus_hfi_state state)
+{
+ mutex_lock(&device->write_lock);
+ mutex_lock(&device->read_lock);
+ device->state = state;
+ mutex_unlock(&device->write_lock);
+ mutex_unlock(&device->read_lock);
+}
+
+static inline bool venus_hfi_core_in_valid_state(
+ struct venus_hfi_device *device)
+{
+ return device->state != VENUS_STATE_DEINIT;
+}
+
+static void venus_hfi_dump_packet(u8 *packet)
+{
+ u32 c = 0, packet_size = *(u32 *)packet;
+ const int row_size = 32;
+ /* row must contain enough for 0xdeadbaad * 8 to be converted into
+ * "de ad ba ab " * 8 + '\0' */
+ char row[3 * row_size];
+
+ for (c = 0; c * row_size < packet_size; ++c) {
+ int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+ packet_size % row_size : row_size;
+ hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+ row_size, 4, row, sizeof(row), false);
+ dprintk(VIDC_PKT, "%s\n", row);
+ }
+}
+
+static void venus_hfi_sim_modify_cmd_packet(u8 *packet,
+ struct venus_hfi_device *device)
+{
+ struct hfi_cmd_sys_session_init_packet *sys_init;
+ struct hal_session *session = NULL;
+ u8 i;
+ phys_addr_t fw_bias = 0;
+
+ if (!device || !packet) {
+ dprintk(VIDC_ERR, "Invalid Param\n");
+ return;
+ } else if (!device->hal_data->firmware_base
+ || is_iommu_present(device->res)) {
+ return;
+ }
+
+ fw_bias = device->hal_data->firmware_base;
+ sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
+
+ /* Ideally we should acquire device->session_lock. If we acquire
+ * we may go to deadlock with inst->*_lock between two threads.
+ * Ex : in the forward path we acquire inst->internalbufs.lock and
+ * session_lock and in the reverse path, we acquire session_lock and
+ * internalbufs.lock. So this may introduce deadlock. So we are not
+ * doing that. On virtio it is less likely to run two sessions
+ * concurrently. So it should be fine */
+
+ session = hfi_process_get_session(
+ &device->sess_head, sys_init->session_id);
+ if (!session) {
+ dprintk(VIDC_DBG, "%s :Invalid session id: %x\n",
+ __func__, sys_init->session_id);
+ return;
+ }
+ switch (sys_init->packet_type) {
+ case HFI_CMD_SESSION_EMPTY_BUFFER:
+ if (session->is_decoder) {
+ struct hfi_cmd_session_empty_buffer_compressed_packet
+ *pkt = (struct
+ hfi_cmd_session_empty_buffer_compressed_packet
+ *) packet;
+ pkt->packet_buffer -= fw_bias;
+ } else {
+ struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ *pkt = (struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ *) packet;
+ pkt->packet_buffer -= fw_bias;
+ }
+ break;
+ case HFI_CMD_SESSION_FILL_BUFFER:
+ {
+ struct hfi_cmd_session_fill_buffer_packet *pkt =
+ (struct hfi_cmd_session_fill_buffer_packet *)packet;
+ pkt->packet_buffer -= fw_bias;
+ break;
+ }
+ case HFI_CMD_SESSION_SET_BUFFERS:
+ {
+ struct hfi_cmd_session_set_buffers_packet *pkt =
+ (struct hfi_cmd_session_set_buffers_packet *)packet;
+ if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+ pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ buff->buffer_addr -= fw_bias;
+ if (buff->extra_data_addr >= fw_bias)
+ buff->extra_data_addr -= fw_bias;
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] -= fw_bias;
+ }
+ break;
+ }
+ case HFI_CMD_SESSION_RELEASE_BUFFERS:
+ {
+ struct hfi_cmd_session_release_buffer_packet *pkt =
+ (struct hfi_cmd_session_release_buffer_packet *)packet;
+ if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+ pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ buff->buffer_addr -= fw_bias;
+ buff->extra_data_addr -= fw_bias;
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] -= fw_bias;
+ }
+ break;
+ }
+ case HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER:
+ {
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt =
+ (struct hfi_cmd_session_parse_sequence_header_packet *)
+ packet;
+ pkt->packet_buffer -= fw_bias;
+ break;
+ }
+ case HFI_CMD_SESSION_GET_SEQUENCE_HEADER:
+ {
+ struct hfi_cmd_session_get_sequence_header_packet *pkt =
+ (struct hfi_cmd_session_get_sequence_header_packet *)
+ packet;
+ pkt->packet_buffer -= fw_bias;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static int venus_hfi_acquire_regulator(struct regulator_info *rinfo)
+{
+ int rc = 0;
+
+ if (rinfo->has_hw_power_collapse) {
+ rc = regulator_set_mode(rinfo->regulator,
+ REGULATOR_MODE_NORMAL);
+ if (rc) {
+ /*
+ * This is somewhat fatal, but nothing we can do
+ * about it. We can't disable the regulator w/o
+ * getting it back under s/w control
+ */
+ dprintk(VIDC_WARN,
+ "Failed to acquire regulator control: %s\n",
+ rinfo->name);
+ } else {
+
+ dprintk(VIDC_DBG,
+ "Acquire regulator control from HW: %s\n",
+ rinfo->name);
+
+ }
+ }
+ WARN_ON(!regulator_is_enabled(rinfo->regulator));
+ return rc;
+}
+
+static int venus_hfi_hand_off_regulator(struct regulator_info *rinfo)
+{
+ int rc = 0;
+
+ if (rinfo->has_hw_power_collapse) {
+ rc = regulator_set_mode(rinfo->regulator,
+ REGULATOR_MODE_FAST);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to hand off regulator control: %s\n",
+ rinfo->name);
+ } else {
+ dprintk(VIDC_DBG,
+ "Hand off regulator control to HW: %s\n",
+ rinfo->name);
+ }
+ }
+
+ return rc;
+}
+
+static int venus_hfi_hand_off_regulators(struct venus_hfi_device *device)
+{
+ struct regulator_info *rinfo;
+ int rc = 0, c = 0;
+
+ venus_hfi_for_each_regulator(device, rinfo) {
+ rc = venus_hfi_hand_off_regulator(rinfo);
+ /*
+ * If one regulator hand off failed, driver should take
+ * the control for other regulators back.
+ */
+ if (rc)
+ goto err_reg_handoff_failed;
+ c++;
+ }
+
+ return rc;
+err_reg_handoff_failed:
+ venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+ venus_hfi_acquire_regulator(rinfo);
+
+ return rc;
+}
+
+static int venus_hfi_acquire_regulators(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ struct regulator_info *rinfo;
+
+ dprintk(VIDC_DBG, "Enabling regulators\n");
+
+ venus_hfi_for_each_regulator(device, rinfo) {
+ if (rinfo->has_hw_power_collapse) {
+ /*
+ * Once driver has the control, it restores the
+ * previous state of regulator. Hence driver no
+ * need to call regulator_enable for these.
+ */
+ rc = venus_hfi_acquire_regulator(rinfo);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed: Aqcuire control: %s\n",
+ rinfo->name);
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set)
+{
+ struct hfi_queue_header *queue;
+ u32 packet_size_in_words, new_write_idx;
+ struct vidc_iface_q_info *qinfo;
+ u32 empty_space, read_idx;
+ u32 *write_ptr;
+
+ if (!info || !packet || !rx_req_is_set) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ qinfo = (struct vidc_iface_q_info *) info;
+ if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+ dprintk(VIDC_WARN, "Queues have already been freed\n");
+ return -EINVAL;
+ }
+
+ queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+ if (!queue) {
+ dprintk(VIDC_ERR, "queue not present\n");
+ return -ENOENT;
+ }
+
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
+
+ packet_size_in_words = (*(u32 *)packet) >> 2;
+ if (!packet_size_in_words) {
+ dprintk(VIDC_ERR, "Zero packet size\n");
+ return -ENODATA;
+ }
+
+ read_idx = queue->qhdr_read_idx;
+
+ empty_space = (queue->qhdr_write_idx >= read_idx) ?
+ (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
+ (read_idx - queue->qhdr_write_idx);
+ if (empty_space <= packet_size_in_words) {
+ queue->qhdr_tx_req = 1;
+ dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
+ empty_space, packet_size_in_words);
+ return -ENOTEMPTY;
+ }
+
+ queue->qhdr_tx_req = 0;
+
+ new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+ write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+ (queue->qhdr_write_idx << 2));
+ if (new_write_idx < queue->qhdr_q_size) {
+ memcpy(write_ptr, packet, packet_size_in_words << 2);
+ } else {
+ new_write_idx -= queue->qhdr_q_size;
+ memcpy(write_ptr, packet, (packet_size_in_words -
+ new_write_idx) << 2);
+ memcpy((void *)qinfo->q_array.align_virtual_addr,
+ packet + ((packet_size_in_words - new_write_idx) << 2),
+ new_write_idx << 2);
+ }
+ /* Memory barrier to make sure packet is written before updating the
+ * write index */
+ mb();
+ queue->qhdr_write_idx = new_write_idx;
+ *rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
+ /*Memory barrier to make sure write index is updated before an
+ * interupt is raised on venus.*/
+ mb();
+ return 0;
+}
+
+static void venus_hfi_hal_sim_modify_msg_packet(u8 *packet,
+ struct venus_hfi_device *device)
+{
+ struct hfi_msg_sys_session_init_done_packet *sys_idle;
+ struct hal_session *session = NULL;
+ phys_addr_t fw_bias = 0;
+
+ if (!device || !packet) {
+ dprintk(VIDC_ERR, "Invalid Param\n");
+ return;
+ } else if (!device->hal_data->firmware_base
+ || is_iommu_present(device->res)) {
+ return;
+ }
+
+ fw_bias = device->hal_data->firmware_base;
+ sys_idle = (struct hfi_msg_sys_session_init_done_packet *)packet;
+ if (&device->session_lock) {
+ mutex_lock(&device->session_lock);
+ session = hfi_process_get_session(
+ &device->sess_head, sys_idle->session_id);
+ mutex_unlock(&device->session_lock);
+ }
+ if (!session) {
+ dprintk(VIDC_DBG, "%s: Invalid session id: %x\n",
+ __func__, sys_idle->session_id);
+ return;
+ }
+ switch (sys_idle->packet_type) {
+ case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+ if (session->is_decoder) {
+ struct
+ hfi_msg_session_fbd_uncompressed_plane0_packet
+ *pkt_uc = (struct
+ hfi_msg_session_fbd_uncompressed_plane0_packet
+ *) packet;
+ pkt_uc->packet_buffer += fw_bias;
+ } else {
+ struct
+ hfi_msg_session_fill_buffer_done_compressed_packet
+ *pkt = (struct
+ hfi_msg_session_fill_buffer_done_compressed_packet
+ *) packet;
+ pkt->packet_buffer += fw_bias;
+ }
+ break;
+ case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+ {
+ struct hfi_msg_session_empty_buffer_done_packet *pkt =
+ (struct hfi_msg_session_empty_buffer_done_packet *)packet;
+ pkt->packet_buffer += fw_bias;
+ break;
+ }
+ case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+ {
+ struct
+ hfi_msg_session_get_sequence_header_done_packet
+ *pkt =
+ (struct hfi_msg_session_get_sequence_header_done_packet *)
+ packet;
+ pkt->sequence_header += fw_bias;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set)
+{
+ struct hfi_queue_header *queue;
+ u32 packet_size_in_words, new_read_idx;
+ u32 *read_ptr;
+ u32 receive_request = 0;
+ struct vidc_iface_q_info *qinfo;
+ int rc = 0;
+
+ if (!info || !packet || !pb_tx_req_is_set) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ qinfo = (struct vidc_iface_q_info *) info;
+ if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+ dprintk(VIDC_WARN, "Queues have already been freed\n");
+ return -EINVAL;
+ }
+ /*Memory barrier to make sure data is valid before
+ *reading it*/
+ mb();
+ queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+ if (!queue) {
+ dprintk(VIDC_ERR, "Queue memory is not allocated\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Do not set receive request for debug queue, if set,
+ * Venus generates interrupt for debug messages even
+ * when there is no response message available.
+ * In general debug queue will not become full as it
+ * is being emptied out for every interrupt from Venus.
+ * Venus will anyway generates interrupt if it is full.
+ */
+ if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
+ receive_request = 1;
+
+ if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+ queue->qhdr_rx_req = receive_request;
+ *pb_tx_req_is_set = 0;
+ dprintk(VIDC_DBG,
+ "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n",
+ receive_request ? "message" : "debug",
+ queue->qhdr_rx_req, queue->qhdr_tx_req,
+ queue->qhdr_read_idx);
+ return -ENODATA;
+ }
+
+ read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+ (queue->qhdr_read_idx << 2));
+ packet_size_in_words = (*read_ptr) >> 2;
+ if (!packet_size_in_words) {
+ dprintk(VIDC_ERR, "Zero packet size\n");
+ return -ENODATA;
+ }
+
+ new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
+ if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
+ && queue->qhdr_read_idx <= queue->qhdr_q_size) {
+ if (new_read_idx < queue->qhdr_q_size) {
+ memcpy(packet, read_ptr,
+ packet_size_in_words << 2);
+ } else {
+ new_read_idx -= queue->qhdr_q_size;
+ memcpy(packet, read_ptr,
+ (packet_size_in_words - new_read_idx) << 2);
+ memcpy(packet + ((packet_size_in_words -
+ new_read_idx) << 2),
+ (u8 *)qinfo->q_array.align_virtual_addr,
+ new_read_idx << 2);
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "BAD packet received, read_idx: %#x, pkt_size: %d\n",
+ queue->qhdr_read_idx, packet_size_in_words << 2);
+ dprintk(VIDC_WARN, "Dropping this packet\n");
+ new_read_idx = queue->qhdr_write_idx;
+ rc = -ENODATA;
+ }
+
+ queue->qhdr_read_idx = new_read_idx;
+
+ if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+ queue->qhdr_rx_req = 0;
+ else
+ queue->qhdr_rx_req = receive_request;
+
+ *pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
+
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
+
+ return rc;
+}
+
+static int venus_hfi_alloc(struct venus_hfi_device *dev, void *mem,
+ u32 size, u32 align, u32 flags, u32 usage)
+{
+ struct vidc_mem_addr *vmem = NULL;
+ struct msm_smem *alloc = NULL;
+ int rc = 0;
+
+ if (!dev || !dev->hal_client || !mem || !size) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+
+ vmem = (struct vidc_mem_addr *)mem;
+ dprintk(VIDC_INFO, "start to alloc size: %d, flags: %d\n", size, flags);
+
+ venus_hfi_power_enable(dev);
+
+ alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
+ if (!alloc) {
+ dprintk(VIDC_ERR, "Alloc failed\n");
+ rc = -ENOMEM;
+ goto fail_smem_alloc;
+ }
+ dprintk(VIDC_DBG, "venus_hfi_alloc: ptr = %p, size = %d\n",
+ alloc->kvaddr, size);
+ rc = msm_smem_cache_operations(dev->hal_client, alloc,
+ SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to clean cache\n");
+ dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+ }
+ vmem->mem_size = alloc->size;
+ vmem->mem_data = alloc;
+ vmem->align_virtual_addr = alloc->kvaddr;
+ vmem->align_device_addr = alloc->device_addr;
+ return rc;
+fail_smem_alloc:
+ return rc;
+}
+
+static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem)
+{
+ if (!dev || !mem) {
+ dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem);
+ return;
+ }
+
+ if (venus_hfi_power_on(dev))
+ dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
+
+ msm_smem_free(dev->hal_client, mem);
+}
+
+static void venus_hfi_write_register(
+ struct venus_hfi_device *device, u32 reg, u32 value)
+{
+ u32 hwiosymaddr = reg;
+ u8 *base_addr;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+ if (device->clk_state != ENABLED_PREPARED) {
+ dprintk(VIDC_WARN,
+ "HFI Write register failed : Clocks are OFF\n");
+ return;
+ }
+
+ base_addr = device->hal_data->register_base;
+ dprintk(VIDC_DBG, "Base addr: %p, written to: %#x, Value: %#x...\n",
+ base_addr, hwiosymaddr, value);
+ base_addr += hwiosymaddr;
+ writel_relaxed(value, base_addr);
+ wmb();
+}
+
+static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)
+{
+ int rc = 0;
+ u8 *base_addr;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ if (device->clk_state != ENABLED_PREPARED) {
+ dprintk(VIDC_WARN,
+ "HFI Read register failed : Clocks are OFF\n");
+ return -EINVAL;
+ }
+ base_addr = device->hal_data->register_base;
+
+ rc = readl_relaxed(base_addr + reg);
+ rmb();
+ dprintk(VIDC_DBG, "Base addr: %p, read from: %#x, value: %#x...\n",
+ base_addr, reg, rc);
+
+ return rc;
+}
+
+static void venus_hfi_set_registers(struct venus_hfi_device *device)
+{
+ struct reg_set *reg_set;
+ int i;
+
+ if (!device->res) {
+ dprintk(VIDC_ERR,
+ "device resources null, cannot set registers\n");
+ return;
+ }
+
+ reg_set = &device->res->reg_set;
+ for (i = 0; i < reg_set->count; i++) {
+ venus_hfi_write_register(device,
+ reg_set->reg_tbl[i].reg,
+ reg_set->reg_tbl[i].value);
+ }
+}
+
+static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
+{
+ u32 ctrl_status = 0, count = 0, rc = 0;
+ int max_tries = 100;
+ venus_hfi_write_register(device,
+ VIDC_WRAPPER_INTR_MASK,
+ VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
+
+ while (!ctrl_status && count < max_tries) {
+ ctrl_status = venus_hfi_read_register(
+ device,
+ VIDC_CPU_CS_SCIACMDARG0);
+ if ((ctrl_status & 0xFE) == 0x4) {
+ dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
+ break;
+ }
+ usleep_range(500, 1000);
+ count++;
+ }
+ if (count >= max_tries)
+ rc = -ETIME;
+ return rc;
+}
+
+static void venus_hfi_iommu_detach(void *dev)
+{
+ struct context_bank_info *cb;
+ struct venus_hfi_device *device = dev;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
+ return;
+ }
+
+ list_for_each_entry(cb, &device->res->context_banks, list) {
+ if (cb->dev)
+ arm_iommu_detach_device(cb->dev);
+ if (cb->mapping)
+ arm_iommu_release_mapping(cb->mapping);
+ }
+}
+
+#define BUS_LOAD(__w, __h, __fps) (\
+ /* Something's fishy if the width & height aren't macroblock aligned */\
+ BUILD_BUG_ON_ZERO(!IS_ALIGNED(__h, 16) || !IS_ALIGNED(__w, 16)) ?: \
+ (__h >> 4) * (__w >> 4) * __fps)
+
+static const u32 venus_hfi_bus_table[] = {
+ BUS_LOAD(0, 0, 0),
+ BUS_LOAD(640, 480, 30),
+ BUS_LOAD(640, 480, 60),
+ BUS_LOAD(1280, 736, 30),
+ BUS_LOAD(1280, 736, 60),
+ BUS_LOAD(1920, 1088, 30),
+ BUS_LOAD(1920, 1088, 60),
+ BUS_LOAD(3840, 2176, 24),
+ BUS_LOAD(4096, 2176, 24),
+ BUS_LOAD(3840, 2176, 30),
+};
+
+static int venus_hfi_get_bus_vector(struct venus_hfi_device *device,
+ struct bus_info *bus, int load)
+{
+ int num_rows = ARRAY_SIZE(venus_hfi_bus_table);
+ int i, j;
+
+ for (i = 0; i < num_rows; i++) {
+ if (load <= venus_hfi_bus_table[i])
+ break;
+ }
+
+ j = clamp(i, 0, num_rows - 1);
+
+ /* Ensure bus index remains within the supported range,
+ * as specified in the device dtsi file */
+ j = clamp(j, 0, bus->pdata->num_usecases - 1);
+
+ dprintk(VIDC_DBG, "Required bus = %d\n", j);
+ return j;
+}
+
+static bool venus_hfi_is_session_supported(unsigned long sessions_supported,
+ enum vidc_bus_vote_data_session session_type)
+{
+ bool same_codec, same_session_type;
+ int codec_bit, session_type_bit;
+ unsigned long session = session_type;
+
+ if (!sessions_supported || !session)
+ return false;
+
+ /* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
+ codec_bit = ffs(session) - 1;
+ session_type_bit = codec_bit + 1;
+
+ same_codec = test_bit(codec_bit, &sessions_supported) ==
+ test_bit(codec_bit, &session);
+ same_session_type = test_bit(session_type_bit, &sessions_supported) ==
+ test_bit(session_type_bit, &session);
+
+ return same_codec && same_session_type;
+}
+
+static int venus_hfi_vote_bus(struct bus_info *bus, unsigned int bus_vector)
+{
+ int rc = msm_bus_scale_client_update_request(bus->priv, bus_vector);
+ if (!rc) {
+ dprintk(VIDC_PROF, "%s bus %s (%s) to vector %d\n",
+ bus_vector ? "Voting" : "Unvoting",
+ bus->pdata->name,
+ bus->passive ? "passive" : "active",
+ bus_vector);
+ }
+
+ return rc;
+}
+
+static int venus_hfi_vote_passive_buses(void *dev,
+ struct vidc_bus_vote_data *data, int num_data)
+{
+ struct venus_hfi_device *device = dev;
+ struct bus_info *bus = NULL;
+ int rc = 0;
+
+ /*
+ * Neither of these parameters are used (or will be useful in future).
+ * Just keeping these so that the API is consistent with _vote_active\
+ * _buses().
+ */
+ (void)data;
+ (void)num_data;
+
+ venus_hfi_for_each_bus(device, bus) {
+ /* Reject active buses, as those are driven by instance load */
+ if (!bus->passive)
+ continue;
+
+ /*
+ * XXX: Should probably check *_is_session_supported() prior
+ * to voting but probably overkill at this point. So skip the
+ * check for now.
+ */
+ rc = venus_hfi_vote_bus(bus, 1);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed voting for passive bus %s: %d\n",
+ bus->pdata->name, rc);
+ goto vote_fail;
+ }
+ }
+
+vote_fail:
+ return rc;
+}
+
+static int venus_hfi_vote_active_buses(void *dev,
+ struct vidc_bus_vote_data *data, int num_data)
+{
+ struct {
+ struct bus_info *bus;
+ int load;
+ } *aggregate_load_table;
+ int rc = 0, i = 0, num_bus = 0;
+ struct venus_hfi_device *device = dev;
+ struct bus_info *bus = NULL;
+ struct vidc_bus_vote_data *cached_vote_data = NULL;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "Invalid device\n");
+ return -EINVAL;
+ } else if (!num_data) {
+ /* Meh nothing to do */
+ return 0;
+ } else if (!data) {
+ dprintk(VIDC_ERR, "Invalid voting data\n");
+ return -EINVAL;
+ }
+
+ /* (Re-)alloc memory to store the new votes (in case we internally
+ * re-vote after power collapse, which is transparent to client) */
+ cached_vote_data = krealloc(device->bus_load.vote_data, num_data *
+ sizeof(*cached_vote_data), GFP_KERNEL);
+ if (!cached_vote_data) {
+ dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ /* Alloc & init the load table */
+ num_bus = device->res->bus_set.count;
+ aggregate_load_table = kzalloc(sizeof(*aggregate_load_table) * num_bus,
+ GFP_TEMPORARY);
+ if (!aggregate_load_table) {
+ dprintk(VIDC_ERR, "The world is ending (no more memory)\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ i = 0;
+ venus_hfi_for_each_bus(device, bus)
+ aggregate_load_table[i++].bus = bus;
+
+ /* Aggregate the loads for each bus */
+ for (i = 0; i < num_data; ++i) {
+ int j = 0;
+
+ for (j = 0; j < num_bus; ++j) {
+ bool matches = venus_hfi_is_session_supported(
+ aggregate_load_table[j].bus->
+ sessions_supported,
+ data[i].session);
+
+ if (matches) {
+ aggregate_load_table[j].load +=
+ data[i].load;
+ }
+ }
+ }
+
+ /* Now vote for each bus */
+ for (i = 0; i < num_bus; ++i) {
+ int bus_vector = 0;
+ struct bus_info *bus = aggregate_load_table[i].bus;
+ int load = aggregate_load_table[i].load;
+
+ /* Passive buses aren't meant to be scaled by load */
+ if (bus->passive)
+ continue;
+
+ /* Let's avoid voting for imem if allocation failed.
+ * There's no clean way presently to check which buses are
+ * associated with imem. So do a crude check for the bus name,
+ * which relies on the buses being named appropriately. */
+ if (!device->resources.imem.type && strnstr(bus->pdata->name,
+ "ocmem", strlen(bus->pdata->name))) {
+ dprintk(VIDC_DBG, "Skipping voting for %s (no imem)\n",
+ bus->pdata->name);
+ continue;
+ }
+
+ bus_vector = venus_hfi_get_bus_vector(device, bus, load);
+ rc = venus_hfi_vote_bus(bus, bus_vector);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed voting for bus %s @ %d: %d\n",
+ bus->pdata->name, bus_vector, rc);
+ /* Ignore error and try to vote for the rest */
+ rc = 0;
+ }
+ }
+
+ /* Cache the votes */
+ for (i = 0; i < num_data; ++i)
+ cached_vote_data[i] = data[i];
+
+ device->bus_load.vote_data = cached_vote_data;
+ device->bus_load.vote_data_count = num_data;
+
+ kfree(aggregate_load_table);
+err_no_mem:
+ return rc;
+
+}
+
+static int venus_hfi_unvote_buses_of_type(struct venus_hfi_device *device,
+ bool only_passive)
+{
+ struct bus_info *bus = NULL;
+ int rc = 0;
+
+ venus_hfi_for_each_bus(device, bus) {
+ int local_rc = 0;
+
+ if (bus->passive != only_passive)
+ continue;
+
+ local_rc = venus_hfi_vote_bus(bus, 0);
+ if (local_rc) {
+ rc = rc ?: local_rc;
+ dprintk(VIDC_ERR,
+ "Failed unvoting passive bus %s: %d\n",
+ bus->pdata->name, rc);
+ }
+ }
+
+ return rc;
+}
+
+static int venus_hfi_unvote_passive_buses(void *dev)
+{
+ return venus_hfi_unvote_buses_of_type(dev, true);
+}
+
+static int venus_hfi_unvote_active_buses(void *dev)
+{
+ return venus_hfi_unvote_buses_of_type(dev, false);
+}
+
+static int venus_hfi_unvote_buses(void *dev)
+{
+ venus_hfi_unvote_active_buses(dev);
+ venus_hfi_unvote_passive_buses(dev);
+
+ return 0;
+}
+
+static int venus_hfi_vote_buses(void *dev,
+ struct vidc_bus_vote_data *data, int num_data)
+{
+ int rc = venus_hfi_vote_passive_buses(dev, data, num_data);
+ rc = rc ?: venus_hfi_vote_active_buses(dev, data, num_data);
+
+ if (rc)
+ goto fail_vote;
+
+ return 0;
+fail_vote:
+ venus_hfi_unvote_buses(dev);
+ return rc;
+}
+
+static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
+ void *pkt);
+
+static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
+ void *pkt)
+{
+ int result = -EPERM;
+ if (!device || !pkt) {
+ dprintk(VIDC_ERR, "Invalid Params");
+ return -EINVAL;
+ }
+ mutex_lock(&device->write_lock);
+ result = venus_hfi_iface_cmdq_write_nolock(device, pkt);
+ mutex_unlock(&device->write_lock);
+ return result;
+}
+
+static int venus_hfi_core_set_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr, void *resource_value,
+ bool locked)
+{
+ struct hfi_cmd_sys_set_resource_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ int rc = 0;
+ struct venus_hfi_device *dev;
+
+ if (!device || !resource_hdr || !resource_value) {
+ dprintk(VIDC_ERR, "set_res: Invalid Params\n");
+ return -EINVAL;
+ }
+
+ dev = device;
+ pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
+
+ rc = call_hfi_pkt_op(dev, sys_set_resource,
+ pkt, resource_hdr, resource_value);
+ if (rc) {
+ dprintk(VIDC_ERR, "set_res: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ rc = locked ? venus_hfi_iface_cmdq_write(dev, pkt) :
+ venus_hfi_iface_cmdq_write_nolock(dev, pkt);
+ if (rc)
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_core_release_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr)
+{
+ struct hfi_cmd_sys_release_resource_packet pkt;
+ int rc = 0;
+ struct venus_hfi_device *dev;
+
+ if (!device || !resource_hdr) {
+ dprintk(VIDC_ERR, "Inv-Params in rel_res\n");
+ return -EINVAL;
+ } else {
+ dev = device;
+ }
+
+ rc = call_hfi_pkt_op(dev, sys_release_resource,
+ &pkt, resource_hdr);
+ if (rc) {
+ dprintk(VIDC_ERR, "release_res: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static DECLARE_COMPLETION(pc_prep_done);
+static DECLARE_COMPLETION(release_resources_done);
+
+static int venus_hfi_alloc_imem(void *dev, unsigned long size)
+{
+ struct imem *imem = NULL;
+ struct venus_hfi_device *device = dev;
+ int rc = 0;
+
+ if (!device || !size)
+ return -EINVAL;
+
+ imem = &device->resources.imem;
+ if (imem->type) {
+ dprintk(VIDC_ERR, "IMEM of type %d already allocated\n",
+ imem->type);
+ return -ENOMEM;
+ }
+
+ switch (device->res->imem_type) {
+ case IMEM_OCMEM:
+ {
+ struct ocmem_buf *ocmem_buffer =
+ ocmem_allocate(OCMEM_VIDEO, size);
+ if (IS_ERR_OR_NULL(ocmem_buffer)) {
+ rc = PTR_ERR(ocmem_buffer) ?: -ENOMEM;
+ goto imem_alloc_failed;
+ }
+
+ imem->ocmem.buf = ocmem_buffer;
+ break;
+ }
+ case IMEM_VMEM:
+ {
+ phys_addr_t vmem_buffer = 0;
+
+ rc = vmem_allocate(size, &vmem_buffer);
+ if (rc) {
+ goto imem_alloc_failed;
+ } else if (!vmem_buffer) {
+ rc = -ENOMEM;
+ goto imem_alloc_failed;
+ }
+
+ imem->vmem = vmem_buffer;
+ break;
+ }
+ default:
+ rc = -ENOTSUPP;
+ goto imem_alloc_failed;
+ }
+
+ imem->type = device->res->imem_type;
+ dprintk(VIDC_DBG, "Allocated %ld bytes of IMEM of type %d\n", size,
+ imem->type);
+ return 0;
+imem_alloc_failed:
+ imem->type = IMEM_NONE;
+ return rc;
+}
+
+static int venus_hfi_free_imem(struct venus_hfi_device *device)
+{
+ struct imem *imem = NULL;
+ int rc = 0;
+
+ if (!device)
+ return -EINVAL;
+
+
+ imem = &device->resources.imem;
+ switch (imem->type) {
+ case IMEM_NONE:
+ /* Follow the semantics of free(NULL), which is a no-op. */
+ break;
+ case IMEM_OCMEM:
+ rc = ocmem_free(OCMEM_VIDEO, imem->ocmem.buf);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to free ocmem\n");
+ goto imem_free_failed;
+ }
+
+ break;
+ case IMEM_VMEM:
+ vmem_free(imem->vmem);
+ break;
+ default:
+ rc = -ENOTSUPP;
+ goto imem_free_failed;
+ }
+
+ imem->type = IMEM_NONE;
+ return 0;
+
+imem_free_failed:
+ return rc;
+}
+
+static int venus_hfi_set_imem(struct venus_hfi_device *device,
+ struct imem *imem, bool locked)
+{
+ struct vidc_resource_hdr rhdr;
+ phys_addr_t addr = 0;
+ int rc = 0;
+
+ if (!device || !device->res || !imem) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p, imem: %p\n",
+ device, imem);
+ return -EINVAL;
+ }
+
+ rhdr.resource_handle = imem; /* cookie */
+ rhdr.size = device->res->imem_size;
+ rhdr.resource_id = VIDC_RESOURCE_NONE;
+
+ switch (imem->type) {
+ case IMEM_OCMEM:
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ addr = imem->ocmem.buf->addr;
+ /* Just for sanity */
+ if (imem->ocmem.buf->len != rhdr.size) {
+ dprintk(VIDC_ERR,
+ "ocmem buffer size unexpectedly small (expected %d, have %lu)\n",
+ rhdr.size, imem->ocmem.buf->len);
+ rc = -EINVAL;
+ goto imem_set_failed;
+ }
+
+ break;
+ case IMEM_VMEM:
+ rhdr.resource_id = VIDC_RESOURCE_VMEM;
+ addr = imem->vmem;
+ break;
+ default:
+ dprintk(VIDC_ERR, "IMEM of type %d unsupported\n", imem->type);
+ rc = -ENOTSUPP;
+ goto imem_set_failed;
+ }
+
+ BUG_ON(!addr);
+
+ rc = venus_hfi_core_set_resource(device, &rhdr, (void *)addr, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set IMEM on driver\n");
+ goto imem_set_failed;
+ }
+
+ dprintk(VIDC_DBG,
+ "Managed to set IMEM buffer of type %d sized %d bytes at %pa\n",
+ rhdr.resource_id, rhdr.size, &addr);
+
+ rc = venus_hfi_vote_buses(device, device->bus_load.vote_data,
+ device->bus_load.vote_data_count);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to vote for buses after setting imem: %d\n",
+ rc);
+ }
+
+imem_set_failed:
+ return rc;
+}
+
+static int venus_hfi_unset_imem(struct venus_hfi_device *device)
+{
+ struct vidc_resource_hdr rhdr;
+ struct imem *imem = NULL;
+ int rc = 0;
+ phys_addr_t addr = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid params, device: %p\n",
+ __func__, device);
+ rc = -EINVAL;
+ goto imem_unset_failed;
+ }
+
+ mutex_lock(&device->write_lock);
+ mutex_lock(&device->read_lock);
+ rc = venus_hfi_core_in_valid_state(device);
+ mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->write_lock);
+ if (!rc) {
+ dprintk(VIDC_WARN, "Core is in bad state, won't unset imem\n");
+ rc = -EIO;
+ goto imem_unset_failed;
+ }
+
+ imem = &device->resources.imem;
+ switch (imem->type) {
+ case IMEM_OCMEM:
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ addr = imem->ocmem.buf->addr;
+ break;
+ case IMEM_VMEM:
+ rhdr.resource_id = VIDC_RESOURCE_VMEM;
+ addr = imem->vmem;
+ break;
+ default:
+ dprintk(VIDC_ERR, "IMEM of type %d unsupported\n", imem->type);
+ rc = -ENOTSUPP;
+ goto imem_unset_failed;
+ }
+
+ if (!addr) {
+ dprintk(VIDC_INFO, "Trying to unset IMEM which is not set\n");
+ rc = -EINVAL;
+ goto imem_unset_failed;
+ }
+
+ rhdr.resource_handle = imem; /* cookie */
+ rhdr.size = device->res->imem_size;
+
+ init_completion(&release_resources_done);
+
+ rc = venus_hfi_core_release_resource(device, &rhdr);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to unset imem on driver\n");
+ goto imem_unset_failed;
+ }
+
+ if (!wait_for_completion_timeout(&release_resources_done,
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout))) {
+ dprintk(VIDC_ERR,
+ "Wait timedout in releasing IMEM\n");
+ rc = -EIO;
+ goto imem_unset_failed;
+ }
+
+imem_unset_failed:
+ return rc;
+}
+
+static int venus_hfi_alloc_set_imem(struct venus_hfi_device *device,
+ bool locked)
+{
+ int rc = 0;
+
+ rc = venus_hfi_alloc_imem(device, device->res->imem_size);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate imem: %d\n", rc);
+ goto alloc_failed;
+ }
+
+ rc = venus_hfi_set_imem(device, &device->resources.imem, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set imem to core: %d\n", rc);
+ goto set_failed;
+ }
+
+ return 0;
+set_failed:
+ venus_hfi_free_imem(device);
+alloc_failed:
+ return rc;
+}
+
+static int venus_hfi_unset_free_imem(struct venus_hfi_device *device)
+{
+ int rc = 0;
+
+ rc = venus_hfi_unset_imem(device);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to unset imem: %d\n", rc);
+ goto unset_failed;
+ }
+
+ rc = venus_hfi_free_imem(device);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to free imem: %d\n", rc);
+ goto free_failed;
+ }
+
+unset_failed:
+free_failed:
+ return rc;
+}
+
+static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
+{
+ int ret;
+
+ ret = qcom_scm_set_video_state(state, 0);
+ if (ret) {
+ dprintk(VIDC_ERR, "Failed scm_call %d\n", ret);
+ return ret;
+ }
+
+ dprintk(VIDC_DBG, "Set state %d\n", state);
+
+ return 0;
+}
+
+static inline int venus_hfi_reset_core(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ venus_hfi_write_register(device, VIDC_CTRL_INIT, 0x1);
+ rc = venus_hfi_core_start_cpu(device);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to start core\n");
+ return rc;
+}
+
+static struct clock_info *venus_hfi_get_clock(struct venus_hfi_device *device,
+ char *name)
+{
+ struct clock_info *vc;
+
+ venus_hfi_for_each_clock(device, vc) {
+ if (!strcmp(vc->name, name))
+ return vc;
+ }
+ dprintk(VIDC_WARN, "%s Clock %s not found\n", __func__, name);
+
+ return NULL;
+}
+
+static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock,
+ int num_mbs_per_sec, int codecs_enabled)
+{
+ int num_rows = clock->count;
+ struct load_freq_table *table = clock->load_freq_tbl;
+ unsigned long freq = table[0].freq;
+ int i;
+
+ if (!num_mbs_per_sec && num_rows > 1)
+ return table[num_rows - 1].freq;
+
+ for (i = 0; i < num_rows; i++) {
+ bool matches = venus_hfi_is_session_supported(
+ table[i].supported_codecs, codecs_enabled);
+ if (!matches)
+ continue;
+
+ if (num_mbs_per_sec > table[i].load)
+ break;
+
+ freq = table[i].freq;
+ }
+
+ return freq;
+}
+
+static unsigned long venus_hfi_get_core_clock_rate(void *dev)
+{
+ struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+ struct clock_info *vc;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, device);
+ return -EINVAL;
+ }
+
+ vc = venus_hfi_get_clock(device, "core_clk");
+ if (vc)
+ return clk_get_rate(vc->clk);
+ else
+ return 0;
+}
+
+static int venus_hfi_suspend(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+ return -EINVAL;
+ }
+ dprintk(VIDC_INFO, "%s\n", __func__);
+
+ if (device->power_enabled) {
+ rc = flush_delayed_work(&venus_hfi_pm_work);
+ dprintk(VIDC_INFO, "%s flush delayed work %d\n", __func__, rc);
+ }
+ return 0;
+}
+
+static enum hal_default_properties venus_hfi_get_default_properties(void *dev)
+{
+ enum hal_default_properties prop = 0;
+ struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+ return -EINVAL;
+ }
+
+ if (device->packetization_type == HFI_PACKETIZATION_3XX)
+ prop = HAL_VIDEO_DYNAMIC_BUF_MODE;
+
+ return prop;
+}
+
+static int venus_hfi_halt_axi(struct venus_hfi_device *device)
+{
+ u32 reg;
+ int rc = 0;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", device);
+ return -EINVAL;
+ }
+ /*
+ * Driver needs to make sure that clocks are enabled to read Venus AXI
+ * registers. If not skip AXI HALT.
+ */
+ if (device->clk_state != ENABLED_PREPARED) {
+ dprintk(VIDC_WARN,
+ "Clocks are OFF, skipping AXI HALT\n");
+ return -EINVAL;
+ }
+
+ /* Halt AXI and AXI IMEM VBIF Access */
+ reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
+ reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+ venus_hfi_write_register(device, VENUS_VBIF_AXI_HALT_CTRL0, reg);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout(device->hal_data->register_base
+ + VENUS_VBIF_AXI_HALT_CTRL1,
+ reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+
+ return rc;
+}
+
+static inline int venus_hfi_power_off(struct venus_hfi_device *device)
+{
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ if (!device->power_enabled) {
+ dprintk(VIDC_DBG, "Power already disabled\n");
+ return 0;
+ }
+
+ rc = venus_hfi_halt_axi(device);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to halt AXI\n");
+ return 0;
+ }
+
+ dprintk(VIDC_DBG, "Entering power collapse\n");
+ rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to suspend video core %d\n", rc);
+ goto err_tzbsp_suspend;
+ }
+ /*
+ * For some regulators, driver might have transfered the control to HW.
+ * So before touching any clocks, driver should get the regulator
+ * control back. Acquire regulators also makes sure that the regulators
+ * are turned ON. So driver can touch the clocks safely.
+ */
+
+ rc = venus_hfi_acquire_regulators(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to enable gdsc in %s Err code = %d\n",
+ __func__, rc);
+ goto err_acquire_regulators;
+ }
+ venus_hfi_disable_unprepare_clks(device);
+ rc = venus_hfi_disable_regulators(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to disable gdsc\n");
+ goto err_disable_regulators;
+ }
+
+ venus_hfi_unvote_buses(device);
+ device->power_enabled = false;
+ dprintk(VIDC_INFO, "Venus power collapsed\n");
+
+ return rc;
+
+err_disable_regulators:
+ if (venus_hfi_prepare_enable_clks(device))
+ dprintk(VIDC_ERR, "Failed prepare_enable_clks\n");
+ if (venus_hfi_hand_off_regulators(device))
+ dprintk(VIDC_ERR, "Failed hand_off_regulators\n");
+err_acquire_regulators:
+ if (venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME))
+ dprintk(VIDC_ERR, "Failed TZBSP_RESUME\n");
+err_tzbsp_suspend:
+ return rc;
+}
+
+static inline int venus_hfi_power_on(struct venus_hfi_device *device)
+{
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ if (device->power_enabled)
+ return 0;
+
+ dprintk(VIDC_DBG, "Resuming from power collapse\n");
+ rc = venus_hfi_vote_buses(device, device->bus_load.vote_data,
+ device->bus_load.vote_data_count);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale buses\n");
+ goto err_vote_buses;
+ }
+
+ /* At this point driver has the control for all regulators */
+ rc = venus_hfi_enable_regulators(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to enable GDSC in %s Err code = %d\n",
+ __func__, rc);
+ goto err_enable_gdsc;
+ }
+
+ rc = venus_hfi_prepare_enable_clks(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to enable clocks\n");
+ goto err_enable_clk;
+ }
+
+ /* Reboot the firmware */
+ rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
+ goto err_set_video_state;
+ }
+
+ rc = venus_hfi_hand_off_regulators(device);
+ if (rc)
+ dprintk(VIDC_WARN, "Failed to handoff control to HW %d\n", rc);
+
+ /*
+ * Re-program all of the registers that get reset as a result of
+ * regulator_disable() and _enable()
+ */
+ venus_hfi_set_registers(device);
+
+ venus_hfi_write_register(device, VIDC_UC_REGION_ADDR,
+ (u32)device->iface_q_table.align_device_addr);
+ venus_hfi_write_register(device, VIDC_UC_REGION_SIZE, SHARED_QSIZE);
+ venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG2,
+ (u32)device->iface_q_table.align_device_addr);
+
+ if (device->sfr.align_device_addr)
+ venus_hfi_write_register(device, VIDC_SFR_ADDR,
+ (u32)device->sfr.align_device_addr);
+ if (device->qdss.align_device_addr)
+ venus_hfi_write_register(device, VIDC_MMAP_ADDR,
+ (u32)device->qdss.align_device_addr);
+
+ /* Wait for boot completion */
+ rc = venus_hfi_reset_core(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to reset venus core\n");
+ goto err_reset_core;
+ }
+
+ /*
+ * Set the flag here to skip venus_hfi_power_on() which is
+ * being called again via *_alloc_set_imem() if imem is enabled
+ */
+ device->power_enabled = true;
+
+ /*
+ * write_lock is already acquired at this point, so to avoid
+ * recursive lock in cmdq_write function, call nolock version
+ * of alloc_icmem
+ */
+ WARN_ON(!mutex_is_locked(&device->write_lock));
+ rc = venus_hfi_alloc_set_imem(device, false);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate IMEM");
+ goto err_alloc_imem;
+ }
+
+ dprintk(VIDC_INFO, "Resumed from power collapse\n");
+ return rc;
+
+err_alloc_imem:
+err_reset_core:
+ venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+err_set_video_state:
+ venus_hfi_disable_unprepare_clks(device);
+err_enable_clk:
+ venus_hfi_disable_regulators(device);
+err_enable_gdsc:
+ venus_hfi_unvote_buses(device);
+err_vote_buses:
+ device->power_enabled = false;
+ dprintk(VIDC_ERR, "Failed to resume from power collapse\n");
+ return rc;
+}
+
+static int venus_hfi_power_enable(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ mutex_lock(&device->write_lock);
+ rc = venus_hfi_power_on(device);
+ if (rc)
+ dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__);
+ mutex_unlock(&device->write_lock);
+
+ return rc;
+}
+
+static int venus_hfi_scale_clocks(void *dev, int load, int codecs_enabled)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+ struct clock_info *cl;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid args: %p\n", device);
+ return -EINVAL;
+ }
+ device->clk_load = load;
+ device->codecs_enabled = codecs_enabled;
+
+ venus_hfi_for_each_clock(device, cl) {
+ if (cl->count) {/* has_scaling */
+ unsigned long rate = venus_hfi_get_clock_rate(cl, load,
+ codecs_enabled);
+ rc = clk_set_rate(cl->clk, rate);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set clock rate %lu %s: %d\n",
+ rate, cl->name, rc);
+ break;
+ }
+
+ dprintk(VIDC_PROF, "Scaling clock %s to %lu\n",
+ cl->name, rate);
+ }
+ }
+
+ return rc;
+}
+
+static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
+ void *pkt)
+{
+ u32 rx_req_is_set = 0;
+ struct vidc_iface_q_info *q_info;
+ struct vidc_hal_cmd_pkt_hdr *cmd_packet;
+ int result = -EPERM;
+
+ if (!device || !pkt) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ WARN(!mutex_is_locked(&device->write_lock),
+ "Cmd queue write lock must be acquired");
+ if (!venus_hfi_core_in_valid_state(device)) {
+ dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+ result = -EINVAL;
+ goto err_q_null;
+ }
+
+ cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
+ device->last_packet_type = cmd_packet->packet_type;
+
+ q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ if (!q_info) {
+ dprintk(VIDC_ERR, "cannot write to shared Q's\n");
+ goto err_q_null;
+ }
+
+ if (!q_info->q_array.align_virtual_addr) {
+ dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
+ result = -ENODATA;
+ goto err_q_null;
+ }
+
+ venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device);
+ if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+
+ if (venus_hfi_power_on(device)) {
+ dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
+ goto err_q_write;
+ }
+ if (venus_hfi_scale_clocks(device, device->clk_load,
+ device->codecs_enabled)) {
+ dprintk(VIDC_ERR, "Clock scaling failed\n");
+ goto err_q_write;
+ }
+ if (rx_req_is_set)
+ venus_hfi_write_register(
+ device, VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+
+ if (device->res->sw_power_collapsible) {
+ dprintk(VIDC_DBG,
+ "Cancel and queue delayed work again\n");
+ cancel_delayed_work(&venus_hfi_pm_work);
+ if (!queue_delayed_work(device->venus_pm_workq,
+ &venus_hfi_pm_work,
+ msecs_to_jiffies(
+ msm_vidc_pwr_collapse_delay))) {
+ dprintk(VIDC_DBG,
+ "PM work already scheduled\n");
+ }
+ }
+ result = 0;
+ } else {
+ dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full\n");
+ }
+err_q_write:
+err_q_null:
+ return result;
+}
+
+static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt)
+{
+ u32 tx_req_is_set = 0;
+ int rc = 0;
+ struct vidc_iface_q_info *q_info;
+
+ if (!pkt) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ mutex_lock(&device->read_lock);
+ if (!venus_hfi_core_in_valid_state(device)) {
+ dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+ rc = -EINVAL;
+ goto read_error_null;
+ }
+
+ if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
+ q_array.align_virtual_addr == 0) {
+ dprintk(VIDC_ERR, "cannot read from shared MSG Q's\n");
+ rc = -ENODATA;
+ goto read_error_null;
+ }
+
+ q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+ if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ venus_hfi_hal_sim_modify_msg_packet((u8 *)pkt, device);
+ if (tx_req_is_set)
+ venus_hfi_write_register(
+ device, VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+ rc = 0;
+ } else
+ rc = -ENODATA;
+
+read_error_null:
+ mutex_unlock(&device->read_lock);
+ return rc;
+}
+
+static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
+{
+ u32 tx_req_is_set = 0;
+ int rc = 0;
+ struct vidc_iface_q_info *q_info;
+
+ if (!pkt) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ mutex_lock(&device->read_lock);
+ if (!venus_hfi_core_in_valid_state(device)) {
+ dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+ rc = -EINVAL;
+ goto dbg_error_null;
+ }
+ if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
+ q_array.align_virtual_addr == 0) {
+ dprintk(VIDC_ERR, "cannot read from shared DBG Q's\n");
+ rc = -ENODATA;
+ goto dbg_error_null;
+ }
+ q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+ if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ if (tx_req_is_set)
+ venus_hfi_write_register(
+ device, VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+ rc = 0;
+ } else
+ rc = -ENODATA;
+
+dbg_error_null:
+ mutex_unlock(&device->read_lock);
+ return rc;
+}
+
+static void venus_hfi_set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
+{
+ q_hdr->qhdr_status = 0x1;
+ q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
+ q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
+ q_hdr->qhdr_pkt_size = 0;
+ q_hdr->qhdr_rx_wm = 0x1;
+ q_hdr->qhdr_tx_wm = 0x1;
+ q_hdr->qhdr_rx_req = 0x1;
+ q_hdr->qhdr_tx_req = 0x0;
+ q_hdr->qhdr_rx_irq_status = 0x0;
+ q_hdr->qhdr_tx_irq_status = 0x0;
+ q_hdr->qhdr_read_idx = 0x0;
+ q_hdr->qhdr_write_idx = 0x0;
+}
+
+static void venus_hfi_interface_queues_release(struct venus_hfi_device *device)
+{
+ int i;
+ struct hfi_mem_map_table *qdss;
+ struct hfi_mem_map *mem_map;
+ int num_entries = device->res->qdss_addr_set.count;
+ unsigned long mem_map_table_base_addr;
+ struct context_bank_info *cb;
+
+ mutex_lock(&device->write_lock);
+ mutex_lock(&device->read_lock);
+ if (device->qdss.mem_data) {
+ qdss = (struct hfi_mem_map_table *)
+ device->qdss.align_virtual_addr;
+ qdss->mem_map_num_entries = num_entries;
+ mem_map_table_base_addr =
+ device->qdss.align_device_addr +
+ sizeof(struct hfi_mem_map_table);
+ qdss->mem_map_table_base_addr =
+ (u32)mem_map_table_base_addr;
+ if ((unsigned long)qdss->mem_map_table_base_addr !=
+ mem_map_table_base_addr) {
+ dprintk(VIDC_ERR,
+ "Invalid mem_map_table_base_addr %#lx",
+ mem_map_table_base_addr);
+ }
+ mem_map = (struct hfi_mem_map *)(qdss + 1);
+ cb = msm_smem_get_context_bank(device->hal_client,
+ false, HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+ for (i = 0; cb && i < num_entries; i++) {
+ iommu_unmap(cb->mapping->domain,
+ mem_map[i].virtual_addr,
+ mem_map[i].size);
+ }
+
+ venus_hfi_free(device, device->qdss.mem_data);
+ }
+ venus_hfi_free(device, device->iface_q_table.mem_data);
+ venus_hfi_free(device, device->sfr.mem_data);
+
+ for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+ device->iface_queues[i].q_hdr = NULL;
+ device->iface_queues[i].q_array.mem_data = NULL;
+ device->iface_queues[i].q_array.align_virtual_addr = NULL;
+ device->iface_queues[i].q_array.align_device_addr = 0;
+ }
+ device->iface_q_table.mem_data = NULL;
+ device->iface_q_table.align_virtual_addr = NULL;
+ device->iface_q_table.align_device_addr = 0;
+
+ device->qdss.mem_data = NULL;
+ device->qdss.align_virtual_addr = NULL;
+ device->qdss.align_device_addr = 0;
+
+ device->sfr.mem_data = NULL;
+ device->sfr.align_virtual_addr = NULL;
+ device->sfr.align_device_addr = 0;
+
+ device->mem_addr.mem_data = NULL;
+ device->mem_addr.align_virtual_addr = NULL;
+ device->mem_addr.align_device_addr = 0;
+
+ msm_smem_delete_client(device->hal_client);
+ device->hal_client = NULL;
+ mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->write_lock);
+}
+
+static int venus_hfi_get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev,
+ struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping)
+{
+ int i;
+ int rc = 0;
+ dma_addr_t iova = QDSS_IOVA_START;
+ int num_entries = dev->res->qdss_addr_set.count;
+ struct addr_range *qdss_addr_tbl = dev->res->qdss_addr_set.addr_tbl;
+ phys_addr_t phys;
+
+ if (!num_entries)
+ return -ENODATA;
+
+ for (i = 0; i < num_entries; i++) {
+ if (mapping) {
+ rc = iommu_map(mapping->domain, iova,
+ qdss_addr_tbl[i].start,
+ qdss_addr_tbl[i].size,
+ IOMMU_READ | IOMMU_WRITE);
+
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "IOMMU QDSS mapping failed for addr %#x\n",
+ qdss_addr_tbl[i].start);
+ rc = -ENOMEM;
+ break;
+ }
+ phys = iommu_iova_to_phys(mapping->domain, iova);
+ dprintk(VIDC_ERR,
+ "%s: iova_to_phys : mapped: %#x, got: %pa\n",
+ __func__, qdss_addr_tbl[i].start,
+ &phys);
+ } else {
+ iova = qdss_addr_tbl[i].start;
+ }
+
+ mem_map[i].virtual_addr = (u32)iova;
+ mem_map[i].physical_addr = qdss_addr_tbl[i].start;
+ mem_map[i].size = qdss_addr_tbl[i].size;
+ mem_map[i].attr = 0x0;
+
+ iova += mem_map[i].size;
+ }
+ if (i < num_entries) {
+ dprintk(VIDC_ERR,
+ "QDSS mapping failed, Freeing other entries %d\n", i);
+
+ for (--i; mapping && i >= 0; i--) {
+ iommu_unmap(mapping->domain,
+ mem_map[i].virtual_addr,
+ mem_map[i].size);
+ }
+ }
+ return rc;
+}
+
+static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev)
+{
+ struct hfi_queue_table_header *q_tbl_hdr;
+ struct hfi_queue_header *q_hdr;
+ u32 i;
+ int rc = 0;
+ struct hfi_mem_map_table *qdss;
+ struct hfi_mem_map *mem_map;
+ struct vidc_iface_q_info *iface_q;
+ struct hfi_sfr_struct *vsfr;
+ struct vidc_mem_addr *mem_addr;
+ int offset = 0;
+ int num_entries = dev->res->qdss_addr_set.count;
+ u32 value = 0;
+ phys_addr_t fw_bias = 0;
+ size_t q_size;
+ unsigned long mem_map_table_base_addr;
+ struct context_bank_info *cb;
+
+ q_size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE;
+ mem_addr = &dev->mem_addr;
+ if (!is_iommu_present(dev->res))
+ fw_bias = dev->hal_data->firmware_base;
+ rc = venus_hfi_alloc(dev, (void *) mem_addr, q_size, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
+ if (rc) {
+ dprintk(VIDC_ERR, "iface_q_table_alloc_fail\n");
+ goto fail_alloc_queue;
+ }
+ dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr;
+ dev->iface_q_table.align_device_addr = mem_addr->align_device_addr -
+ fw_bias;
+ dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
+ dev->iface_q_table.mem_data = mem_addr->mem_data;
+ offset += dev->iface_q_table.mem_size;
+
+ for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+ iface_q = &dev->iface_queues[i];
+ iface_q->q_array.align_device_addr = mem_addr->align_device_addr
+ + offset - fw_bias;
+ iface_q->q_array.align_virtual_addr =
+ mem_addr->align_virtual_addr + offset;
+ iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
+ iface_q->q_array.mem_data = NULL;
+ offset += iface_q->q_array.mem_size;
+ iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(
+ dev->iface_q_table.align_virtual_addr, i);
+ venus_hfi_set_queue_hdr_defaults(iface_q->q_hdr);
+ }
+ if ((msm_vidc_fw_debug_mode & HFI_DEBUG_MODE_QDSS) && num_entries) {
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ ALIGNED_QDSS_SIZE, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "qdss_alloc_fail: QDSS messages logging will not work\n");
+ dev->qdss.align_device_addr = 0;
+ } else {
+ dev->qdss.align_device_addr =
+ mem_addr->align_device_addr - fw_bias;
+ dev->qdss.align_virtual_addr =
+ mem_addr->align_virtual_addr;
+ dev->qdss.mem_size = ALIGNED_QDSS_SIZE;
+ dev->qdss.mem_data = mem_addr->mem_data;
+ }
+ }
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ ALIGNED_SFR_SIZE, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
+ if (rc) {
+ dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work\n");
+ dev->sfr.align_device_addr = 0;
+ } else {
+ dev->sfr.align_device_addr = mem_addr->align_device_addr -
+ fw_bias;
+ dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr;
+ dev->sfr.mem_size = ALIGNED_SFR_SIZE;
+ dev->sfr.mem_data = mem_addr->mem_data;
+ }
+ q_tbl_hdr = (struct hfi_queue_table_header *)
+ dev->iface_q_table.align_virtual_addr;
+ q_tbl_hdr->qtbl_version = 0;
+ q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE;
+ q_tbl_hdr->qtbl_qhdr0_offset = sizeof(
+ struct hfi_queue_table_header);
+ q_tbl_hdr->qtbl_qhdr_size = sizeof(
+ struct hfi_queue_header);
+ q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ;
+ q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ;
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+ if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+ iface_q->q_array.align_device_addr) {
+ dprintk(VIDC_ERR, "Invalid CMDQ device address (%pa)\n",
+ &iface_q->q_array.align_device_addr);
+ }
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+ if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+ iface_q->q_array.align_device_addr) {
+ dprintk(VIDC_ERR, "Invalid MSGQ device address (%pa)\n",
+ &iface_q->q_array.align_device_addr);
+ }
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
+ /*
+ * Set receive request to zero on debug queue as there is no
+ * need of interrupt from video hardware for debug messages
+ */
+ q_hdr->qhdr_rx_req = 0;
+ if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+ iface_q->q_array.align_device_addr) {
+ dprintk(VIDC_ERR, "Invalid DBGQ device address (%pa)\n",
+ &iface_q->q_array.align_device_addr);
+ }
+
+ value = (u32)dev->iface_q_table.align_device_addr;
+ if ((ion_phys_addr_t)value !=
+ dev->iface_q_table.align_device_addr) {
+ dprintk(VIDC_ERR,
+ "Invalid iface_q_table device address (%pa)\n",
+ &dev->iface_q_table.align_device_addr);
+ }
+ venus_hfi_write_register(dev, VIDC_UC_REGION_ADDR, value);
+ venus_hfi_write_register(dev, VIDC_UC_REGION_SIZE, SHARED_QSIZE);
+ venus_hfi_write_register(dev, VIDC_CPU_CS_SCIACMDARG2, value);
+ venus_hfi_write_register(dev, VIDC_CPU_CS_SCIACMDARG1, 0x01);
+ if (dev->qdss.mem_data) {
+ qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr;
+ qdss->mem_map_num_entries = num_entries;
+ mem_map_table_base_addr = dev->qdss.align_device_addr +
+ sizeof(struct hfi_mem_map_table);
+ qdss->mem_map_table_base_addr =
+ (u32)mem_map_table_base_addr;
+ if ((ion_phys_addr_t)qdss->mem_map_table_base_addr !=
+ mem_map_table_base_addr) {
+ dprintk(VIDC_ERR,
+ "Invalid mem_map_table_base_addr (%#lx)\n",
+ mem_map_table_base_addr);
+ }
+ mem_map = (struct hfi_mem_map *)(qdss + 1);
+ cb = msm_smem_get_context_bank(dev->hal_client, false,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+ if (!cb) {
+ dprintk(VIDC_ERR,
+ "%s: failed to get context bank\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = venus_hfi_get_qdss_iommu_virtual_addr(dev,
+ mem_map, cb->mapping);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "IOMMU mapping failed, Freeing qdss memdata\n");
+ venus_hfi_free(dev, dev->qdss.mem_data);
+ dev->qdss.mem_data = NULL;
+ dev->qdss.align_virtual_addr = NULL;
+ dev->qdss.align_device_addr = 0;
+ }
+ value = (u32)dev->qdss.align_device_addr;
+ if ((ion_phys_addr_t)value !=
+ dev->qdss.align_device_addr) {
+ dprintk(VIDC_ERR, "Invalid qdss device address (%pa)\n",
+ &dev->qdss.align_device_addr);
+ }
+ if (dev->qdss.align_device_addr)
+ venus_hfi_write_register(dev, VIDC_MMAP_ADDR, value);
+ }
+
+ vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
+ vsfr->bufSize = ALIGNED_SFR_SIZE;
+ value = (u32)dev->sfr.align_device_addr;
+ if ((ion_phys_addr_t)value !=
+ dev->sfr.align_device_addr) {
+ dprintk(VIDC_ERR, "Invalid sfr device address (%pa)\n",
+ &dev->sfr.align_device_addr);
+ }
+ if (dev->sfr.align_device_addr)
+ venus_hfi_write_register(dev, VIDC_SFR_ADDR, value);
+ return 0;
+fail_alloc_queue:
+ return -ENOMEM;
+}
+
+static int venus_hfi_sys_set_debug(struct venus_hfi_device *device, u32 debug)
+{
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ int rc = 0;
+ struct hfi_cmd_sys_set_property_packet *pkt =
+ (struct hfi_cmd_sys_set_property_packet *) &packet;
+
+ rc = call_hfi_pkt_op(device, sys_debug_config, pkt, debug);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Debug mode setting to FW failed\n");
+ return -ENOTEMPTY;
+ }
+ if (venus_hfi_iface_cmdq_write(device, pkt))
+ return -ENOTEMPTY;
+ return 0;
+}
+
+static int venus_hfi_sys_set_coverage(struct venus_hfi_device *device, u32 mode)
+{
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ int rc = 0;
+ struct hfi_cmd_sys_set_property_packet *pkt =
+ (struct hfi_cmd_sys_set_property_packet *) &packet;
+
+ rc = call_hfi_pkt_op(device, sys_coverage_config,
+ pkt, mode);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Coverage mode setting to FW failed\n");
+ return -ENOTEMPTY;
+ }
+ if (venus_hfi_iface_cmdq_write(device, pkt)) {
+ dprintk(VIDC_WARN, "Failed to send coverage pkt to f/w\n");
+ return -ENOTEMPTY;
+ }
+ return 0;
+}
+
+static int venus_hfi_sys_set_idle_message(struct venus_hfi_device *device,
+ bool enable)
+{
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hfi_cmd_sys_set_property_packet *pkt =
+ (struct hfi_cmd_sys_set_property_packet *) &packet;
+ if (!enable) {
+ dprintk(VIDC_DBG, "sys_idle_indicator is not enabled\n");
+ return 0;
+ }
+ call_hfi_pkt_op(device, sys_idle_indicator, pkt, enable);
+ if (venus_hfi_iface_cmdq_write(device, pkt))
+ return -ENOTEMPTY;
+ return 0;
+}
+
+static int venus_hfi_sys_set_power_control(struct venus_hfi_device *device,
+ bool enable)
+{
+ struct regulator_info *rinfo;
+ bool supported = false;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hfi_cmd_sys_set_property_packet *pkt =
+ (struct hfi_cmd_sys_set_property_packet *) &packet;
+
+ venus_hfi_for_each_regulator(device, rinfo) {
+ if (rinfo->has_hw_power_collapse) {
+ supported = true;
+ break;
+ }
+ }
+
+ if (!supported)
+ return 0;
+
+ call_hfi_pkt_op(device, sys_power_control, pkt, enable);
+ if (venus_hfi_iface_cmdq_write(device, pkt))
+ return -ENOTEMPTY;
+ return 0;
+}
+
+static int venus_hfi_core_init(void *device)
+{
+ struct hfi_cmd_sys_init_packet pkt;
+ struct hfi_cmd_sys_get_property_packet version_pkt;
+ int rc = 0;
+ struct list_head *ptr, *next;
+ struct hal_session *session = NULL;
+ struct venus_hfi_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "Invalid device\n");
+ return -ENODEV;
+ }
+
+ venus_hfi_set_state(dev, VENUS_STATE_INIT);
+
+ dev->intr_status = 0;
+
+ mutex_lock(&dev->session_lock);
+ list_for_each_safe(ptr, next, &dev->sess_head) {
+ /* This means that session list is not empty. Kick stale
+ * sessions out of our valid instance list, but keep the
+ * list_head inited so that list_del (in the future, called
+ * by session_clean()) will be valid. When client doesn't close
+ * them, then it is a genuine leak which driver can't fix. */
+ session = list_entry(ptr, struct hal_session, list);
+ list_del_init(&session->list);
+ }
+ INIT_LIST_HEAD(&dev->sess_head);
+ mutex_unlock(&dev->session_lock);
+
+ venus_hfi_set_registers(dev);
+
+ if (!dev->hal_client) {
+ dev->hal_client = msm_smem_new_client(SMEM_DMA, dev->res);
+ if (dev->hal_client == NULL) {
+ dprintk(VIDC_ERR, "Failed to alloc ION_Client\n");
+ rc = -ENODEV;
+ goto err_core_init;
+ }
+
+ dprintk(VIDC_DBG, "Dev_Virt: %pa, Reg_Virt: %p\n",
+ &dev->hal_data->firmware_base,
+ dev->hal_data->register_base);
+
+ rc = venus_hfi_interface_queues_init(dev);
+ if (rc) {
+ dprintk(VIDC_ERR, "failed to init queues\n");
+ rc = -ENOMEM;
+ goto err_core_init;
+ }
+ } else {
+ dprintk(VIDC_ERR, "hal_client exists\n");
+ rc = -EEXIST;
+ goto err_core_init;
+ }
+ enable_irq(dev->hal_data->irq);
+ venus_hfi_write_register(dev, VIDC_CTRL_INIT, 0x1);
+ rc = venus_hfi_core_start_cpu(dev);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to start core\n");
+ rc = -ENODEV;
+ goto err_core_init;
+ }
+
+ rc = call_hfi_pkt_op(dev, sys_init, &pkt, HFI_VIDEO_ARCH_OX);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to create sys init pkt\n");
+ goto err_core_init;
+ }
+ if (venus_hfi_iface_cmdq_write(dev, &pkt)) {
+ rc = -ENOTEMPTY;
+ goto err_core_init;
+ }
+
+ rc = call_hfi_pkt_op(dev, sys_image_version, &version_pkt);
+ if (rc || venus_hfi_iface_cmdq_write(dev, &version_pkt))
+ dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
+
+ return rc;
+err_core_init:
+ venus_hfi_set_state(dev, VENUS_STATE_DEINIT);
+ disable_irq_nosync(dev->hal_data->irq);
+ return rc;
+}
+
+static int venus_hfi_core_release(void *device)
+{
+ struct venus_hfi_device *dev;
+ int rc = 0;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "invalid device\n");
+ return -ENODEV;
+ }
+
+ if (dev->hal_client) {
+ if (venus_hfi_power_enable(device)) {
+ dprintk(VIDC_ERR,
+ "%s: Power enable failed\n", __func__);
+ return -EIO;
+ }
+
+ mutex_lock(&dev->resource_lock);
+ rc = venus_hfi_unset_free_imem(dev);
+ mutex_unlock(&dev->resource_lock);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to unset and free imem in core release: %d\n",
+ rc);
+ if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+ disable_irq_nosync(dev->hal_data->irq);
+ dev->intr_status = 0;
+ }
+ venus_hfi_set_state(dev, VENUS_STATE_DEINIT);
+
+ dprintk(VIDC_INFO, "HAL exited\n");
+ return 0;
+}
+
+static int venus_hfi_get_q_size(struct venus_hfi_device *dev,
+ unsigned int q_index)
+{
+ struct hfi_queue_header *queue;
+ struct vidc_iface_q_info *q_info;
+ u32 write_ptr, read_ptr;
+ u32 rc = 0;
+
+ if (q_index >= VIDC_IFACEQ_NUMQ) {
+ dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
+ return -ENOENT;
+ }
+
+ q_info = &dev->iface_queues[q_index];
+ if (!q_info) {
+ dprintk(VIDC_ERR, "cannot read shared Q's\n");
+ return -ENOENT;
+ }
+
+ queue = (struct hfi_queue_header *)q_info->q_hdr;
+ if (!queue) {
+ dprintk(VIDC_ERR, "queue not present\n");
+ return -ENOENT;
+ }
+
+ write_ptr = (u32)queue->qhdr_write_idx;
+ read_ptr = (u32)queue->qhdr_read_idx;
+ rc = read_ptr - write_ptr;
+ return rc;
+}
+
+static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
+{
+ u32 intr_status = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+ return;
+ }
+
+ intr_status = venus_hfi_read_register(
+ device,
+ VIDC_WRAPPER_INTR_STATUS);
+
+ if (intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK ||
+ intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK ||
+ intr_status &
+ VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK) {
+ device->intr_status |= intr_status;
+ device->reg_count++;
+ dprintk(VIDC_DBG,
+ "INTERRUPT for device: %p: times: %d interrupt_status: %d\n",
+ device, device->reg_count, intr_status);
+ } else {
+ device->spur_count++;
+ dprintk(VIDC_INFO,
+ "SPURIOUS_INTR for device: %p: times: %d interrupt_status: %d\n",
+ device, device->spur_count, intr_status);
+ }
+
+ venus_hfi_write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
+ venus_hfi_write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
+ dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
+}
+
+static int venus_hfi_core_ping(void *device)
+{
+ struct hfi_cmd_sys_ping_packet pkt;
+ int rc = 0;
+ struct venus_hfi_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "invalid device\n");
+ return -ENODEV;
+ }
+
+ rc = call_hfi_pkt_op(dev, sys_ping, &pkt);
+ if (rc) {
+ dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_core_trigger_ssr(void *device,
+ enum hal_ssr_trigger_type type)
+{
+ struct hfi_cmd_sys_test_ssr_packet pkt;
+ int rc = 0;
+ struct venus_hfi_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "invalid device\n");
+ return -ENODEV;
+ }
+
+ rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt);
+ if (rc) {
+ dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_set_property(void *sess,
+ enum hal_property ptype, void *pdata)
+{
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ struct hfi_cmd_session_set_property_packet *pkt =
+ (struct hfi_cmd_session_set_property_packet *) &packet;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+ int rc = 0;
+
+ if (!session || !session->device || !pdata) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype);
+
+ rc = call_hfi_pkt_op(device, session_set_property,
+ pkt, session, ptype, pdata);
+ if (rc) {
+ dprintk(VIDC_ERR, "set property: failed to create packet\n");
+ return -EINVAL;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, pkt))
+ return -ENOTEMPTY;
+
+ return rc;
+}
+
+static int venus_hfi_session_get_property(void *sess,
+ enum hal_property ptype)
+{
+ struct hfi_cmd_session_get_property_packet pkt = {0};
+ struct hal_session *session = sess;
+ int rc = 0;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype);
+
+ rc = call_hfi_pkt_op(device, session_get_property,
+ &pkt, session, ptype);
+ if (rc) {
+ dprintk(VIDC_ERR, "get property profile: pkt failed\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt)) {
+ rc = -ENOTEMPTY;
+ dprintk(VIDC_ERR, "%s cmdq_write error\n", __func__);
+ }
+err_create_pkt:
+ return rc;
+}
+
+static void venus_hfi_set_default_sys_properties(
+ struct venus_hfi_device *device)
+{
+ if (venus_hfi_sys_set_debug(device, msm_vidc_fw_debug))
+ dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n");
+ if (venus_hfi_sys_set_idle_message(device,
+ device->res->sys_idle_indicator || msm_vidc_sys_idle_indicator))
+ dprintk(VIDC_WARN, "Setting idle response ON failed\n");
+ if (venus_hfi_sys_set_power_control(device, msm_vidc_fw_low_power_mode))
+ dprintk(VIDC_WARN, "Setting h/w power collapse ON failed\n");
+}
+
+static int venus_hfi_session_clean(void *session)
+{
+ struct hal_session *sess_close;
+ struct venus_hfi_device *device;
+ if (!session) {
+ dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+ return -EINVAL;
+ }
+ sess_close = session;
+ device = sess_close->device;
+ venus_hfi_flush_debug_queue(sess_close->device, NULL);
+ dprintk(VIDC_DBG, "deleted the session: %p\n",
+ sess_close);
+ mutex_lock(&device->session_lock);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ mutex_unlock(&device->session_lock);
+ return 0;
+}
+
+static void *venus_hfi_session_init(void *device, void *session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type)
+{
+ struct hfi_cmd_sys_session_init_packet pkt;
+ struct hal_session *new_session;
+ struct venus_hfi_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "invalid device\n");
+ return NULL;
+ }
+
+ new_session = (struct hal_session *)
+ kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+ if (!new_session) {
+ dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+ return NULL;
+ }
+ new_session->session_id = session_id;
+ new_session->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER);
+ new_session->device = dev;
+
+ mutex_lock(&dev->session_lock);
+ list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
+
+ venus_hfi_set_default_sys_properties(device);
+
+ if (call_hfi_pkt_op(dev, session_init, &pkt,
+ new_session, session_type, codec_type)) {
+ dprintk(VIDC_ERR, "session_init: failed to create packet\n");
+ goto err_session_init_fail;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ goto err_session_init_fail;
+ return (void *) new_session;
+
+err_session_init_fail:
+ venus_hfi_session_clean(new_session);
+ return NULL;
+}
+
+static int venus_hfi_send_session_cmd(void *session_id,
+ int pkt_type)
+{
+ struct vidc_hal_session_cmd_pkt pkt;
+ int rc = 0;
+ struct hal_session *session = session_id;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "invalid session");
+ return -ENODEV;
+ }
+ device = session->device;
+
+ rc = call_hfi_pkt_op(device, session_cmd,
+ &pkt, pkt_type, session);
+ if (rc) {
+ dprintk(VIDC_ERR, "send session cmd: create pkt failed\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_end(void *session)
+{
+ struct hal_session *sess;
+ if (!session) {
+ dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+ return -EINVAL;
+ }
+ sess = session;
+ if (msm_vidc_fw_coverage) {
+ if (venus_hfi_sys_set_coverage(sess->device,
+ msm_vidc_fw_coverage))
+ dprintk(VIDC_WARN, "Fw_coverage msg ON failed\n");
+ }
+ return venus_hfi_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_END);
+}
+
+static int venus_hfi_session_abort(void *session)
+{
+ venus_hfi_flush_debug_queue(
+ ((struct hal_session *)session)->device, NULL);
+ return venus_hfi_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_ABORT);
+}
+
+static int venus_hfi_session_set_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct hfi_cmd_session_set_buffers_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !buffer_info) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+
+ pkt = (struct hfi_cmd_session_set_buffers_packet *)packet;
+
+ rc = call_hfi_pkt_op(device, session_set_buffers,
+ pkt, session, buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "set buffers: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type);
+ if (venus_hfi_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_release_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct hfi_cmd_session_release_buffer_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !buffer_info) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+
+ pkt = (struct hfi_cmd_session_release_buffer_packet *) packet;
+
+ rc = call_hfi_pkt_op(device, session_release_buffers,
+ pkt, session, buffer_info);
+ if (rc) {
+ dprintk(VIDC_ERR, "release buffers: failed to create packet\n");
+ goto err_create_pkt;
+ }
+
+ dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type);
+ if (venus_hfi_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_load_res(void *sess)
+{
+ return venus_hfi_send_session_cmd(sess,
+ HFI_CMD_SESSION_LOAD_RESOURCES);
+}
+
+static int venus_hfi_session_release_res(void *sess)
+{
+ return venus_hfi_send_session_cmd(sess,
+ HFI_CMD_SESSION_RELEASE_RESOURCES);
+}
+
+static int venus_hfi_session_start(void *sess)
+{
+ return venus_hfi_send_session_cmd(sess,
+ HFI_CMD_SESSION_START);
+}
+
+static int venus_hfi_session_stop(void *sess)
+{
+ return venus_hfi_send_session_cmd(sess,
+ HFI_CMD_SESSION_STOP);
+}
+
+static int venus_hfi_session_etb(void *sess,
+ struct vidc_frame_data *input_frame)
+{
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !input_frame) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ if (session->is_decoder) {
+ struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
+
+ rc = call_hfi_pkt_op(device, session_etb_decoder,
+ &pkt, session, input_frame);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session etb decoder: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+ dprintk(VIDC_DBG, "Q DECODER INPUT BUFFER\n");
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ } else {
+ struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ pkt;
+
+
+ rc = call_hfi_pkt_op(device, session_etb_encoder,
+ &pkt, session, input_frame);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session etb encoder: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+ dprintk(VIDC_DBG, "Q ENCODER INPUT BUFFER\n");
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ }
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_ftb(void *sess,
+ struct vidc_frame_data *output_frame)
+{
+ struct hfi_cmd_session_fill_buffer_packet pkt;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !output_frame) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ rc = call_hfi_pkt_op(device, session_ftb,
+ &pkt, session, output_frame);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_parse_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !seq_hdr) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ pkt = (struct hfi_cmd_session_parse_sequence_header_packet *) packet;
+
+ rc = call_hfi_pkt_op(device, session_parse_seq_header,
+ pkt, session, seq_hdr);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session parse seq hdr: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_get_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct hfi_cmd_session_get_sequence_header_packet *pkt;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device || !seq_hdr) {
+ dprintk(VIDC_ERR, "Invalid Params\n");
+ return -EINVAL;
+ }
+ device = session->device;
+
+ pkt = (struct hfi_cmd_session_get_sequence_header_packet *) packet;
+
+ rc = call_hfi_pkt_op(device, session_get_seq_hdr,
+ pkt, session, seq_hdr);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session get seq hdr: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_get_buf_req(void *sess)
+{
+ struct hfi_cmd_session_get_property_packet pkt;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "invalid session");
+ return -ENODEV;
+ }
+ device = session->device;
+
+ rc = call_hfi_pkt_op(device, session_get_buf_req,
+ &pkt, session);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Session get buf req: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
+{
+ struct hfi_cmd_session_flush_packet pkt;
+ int rc = 0;
+ struct hal_session *session = sess;
+ struct venus_hfi_device *device;
+
+ if (!session || !session->device) {
+ dprintk(VIDC_ERR, "invalid session");
+ return -ENODEV;
+ }
+ device = session->device;
+
+ rc = call_hfi_pkt_op(device, session_flush,
+ &pkt, session, flush_mode);
+ if (rc) {
+ dprintk(VIDC_ERR, "Session flush: failed to create pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_check_core_registered(
+ struct hal_device_data core, phys_addr_t fw_addr,
+ u8 *reg_addr, u32 reg_size, phys_addr_t irq)
+{
+ struct venus_hfi_device *device;
+ struct list_head *curr, *next;
+
+ if (core.dev_count) {
+ list_for_each_safe(curr, next, &core.dev_head) {
+ device = list_entry(curr,
+ struct venus_hfi_device, list);
+ if (device && device->hal_data->irq == irq &&
+ (CONTAINS(device->hal_data->
+ firmware_base,
+ FIRMWARE_SIZE, fw_addr) ||
+ CONTAINS(fw_addr, FIRMWARE_SIZE,
+ device->hal_data->
+ firmware_base) ||
+ CONTAINS(device->hal_data->
+ register_base,
+ reg_size, reg_addr) ||
+ CONTAINS(reg_addr, reg_size,
+ device->hal_data->
+ register_base) ||
+ OVERLAPS(device->hal_data->
+ register_base,
+ reg_size, reg_addr, reg_size) ||
+ OVERLAPS(reg_addr, reg_size,
+ device->hal_data->
+ register_base, reg_size) ||
+ OVERLAPS(device->hal_data->
+ firmware_base,
+ FIRMWARE_SIZE, fw_addr,
+ FIRMWARE_SIZE) ||
+ OVERLAPS(fw_addr, FIRMWARE_SIZE,
+ device->hal_data->
+ firmware_base,
+ FIRMWARE_SIZE))) {
+ return 0;
+ } else {
+ dprintk(VIDC_INFO, "Device not registered\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ dprintk(VIDC_INFO, "no device Registered\n");
+ }
+ return -EINVAL;
+}
+
+static void venus_hfi_process_sys_watchdog_timeout(
+ struct venus_hfi_device *device)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
+}
+
+static int venus_hfi_core_pc_prep(void *device)
+{
+ struct hfi_cmd_sys_pc_prep_packet pkt;
+ int rc = 0;
+ struct venus_hfi_device *dev = device;
+
+ if (!dev) {
+ dprintk(VIDC_ERR, "invalid device\n");
+ return -ENODEV;
+ }
+
+ rc = call_hfi_pkt_op(dev, sys_pc_prep, &pkt);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
+static int venus_hfi_prepare_pc(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ init_completion(&pc_prep_done);
+ rc = venus_hfi_core_pc_prep(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+ goto err_pc_prep;
+ }
+ rc = wait_for_completion_timeout(&pc_prep_done,
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "Wait interrupted or timeout for PC_PREP_DONE: %d\n",
+ rc);
+ venus_hfi_flush_debug_queue(device, NULL);
+ rc = -EIO;
+ goto err_pc_prep;
+ }
+ rc = 0;
+err_pc_prep:
+ return rc;
+}
+
+static void venus_hfi_pm_hndlr(struct work_struct *work)
+{
+ int rc = 0;
+ u32 ctrl_status = 0;
+ struct venus_hfi_device *device = list_first_entry(
+ &hal_ctxt.dev_head, struct venus_hfi_device, list);
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+ return;
+ }
+ if (!device->power_enabled) {
+ dprintk(VIDC_DBG, "%s: Power already disabled\n",
+ __func__);
+ return;
+ }
+
+ mutex_lock(&device->write_lock);
+ mutex_lock(&device->read_lock);
+ rc = venus_hfi_core_in_valid_state(device);
+ mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->write_lock);
+
+ if (!rc) {
+ dprintk(VIDC_WARN,
+ "Core is in bad state, Skipping power collapse\n");
+ return;
+ }
+
+ dprintk(VIDC_DBG, "Prepare for power collapse\n");
+
+ if (device->resources.imem.type) {
+ mutex_lock(&device->resource_lock);
+ rc = venus_hfi_unset_free_imem(device);
+ mutex_unlock(&device->resource_lock);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to unset IMEM for PC: %d\n",
+ rc);
+ goto err_unset_imem;
+ }
+ }
+
+ rc = venus_hfi_prepare_pc(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
+ goto err_prepare_pc;
+ }
+
+ mutex_lock(&device->write_lock);
+
+ if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) {
+ dprintk(VIDC_DBG,
+ "Last command (%#x) is not PC_PREP cmd\n",
+ device->last_packet_type);
+ goto skip_power_off;
+ }
+
+ if (venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX) ||
+ venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX)) {
+ dprintk(VIDC_DBG, "Cmd/msg queues are not empty\n");
+ goto skip_power_off;
+ }
+
+ ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+ if (!(ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY)) {
+ dprintk(VIDC_DBG,
+ "Venus is not ready for power collapse (%#x)\n",
+ ctrl_status);
+ goto skip_power_off;
+ }
+
+ rc = venus_hfi_power_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed venus power off\n");
+ goto err_power_off;
+ }
+
+ /* Cancel pending delayed works if any */
+ cancel_delayed_work(&venus_hfi_pm_work);
+
+ mutex_unlock(&device->write_lock);
+ return;
+
+err_power_off:
+skip_power_off:
+
+ /*
+ * When power collapse is escaped, driver no need to inform Venus.
+ * Venus is self-sufficient to come out of the power collapse at
+ * any stage. Driver can skip power collapse and continue with
+ * normal execution.
+ */
+
+ /* Cancel pending delayed works if any */
+ cancel_delayed_work(&venus_hfi_pm_work);
+ dprintk(VIDC_WARN, "Power off skipped (last pkt %#x, status: %#x)\n",
+ device->last_packet_type, ctrl_status);
+
+ mutex_unlock(&device->write_lock);
+err_prepare_pc:
+ venus_hfi_alloc_imem(device, device->res->imem_size);
+err_unset_imem:
+ return;
+}
+
+static void venus_hfi_process_msg_event_notify(
+ struct venus_hfi_device *device, void *packet)
+{
+ struct hfi_sfr_struct *vsfr = NULL;
+ struct hfi_msg_event_notify_packet *event_pkt;
+ struct vidc_hal_msg_pkt_hdr *msg_hdr;
+
+ msg_hdr = (struct vidc_hal_msg_pkt_hdr *)packet;
+ event_pkt =
+ (struct hfi_msg_event_notify_packet *)msg_hdr;
+ if (event_pkt && event_pkt->event_id ==
+ HFI_EVENT_SYS_ERROR) {
+
+ venus_hfi_set_state(device, VENUS_STATE_DEINIT);
+
+ /* Once SYS_ERROR received from HW, it is safe to halt the AXI.
+ * With SYS_ERROR, Venus FW may have crashed and HW might be
+ * active and causing unnecessary transactions. Hence it is
+ * safe to stop all AXI transactions from venus sub-system. */
+ if (venus_hfi_halt_axi(device))
+ dprintk(VIDC_WARN,
+ "Failed to halt AXI after SYS_ERROR\n");
+
+ vsfr = (struct hfi_sfr_struct *)
+ device->sfr.align_virtual_addr;
+ if (vsfr) {
+ void *p = memchr(vsfr->rg_data, '\0',
+ vsfr->bufSize);
+ /* SFR isn't guaranteed to be NULL terminated
+ since SYS_ERROR indicates that Venus is in the
+ process of crashing.*/
+ if (p == NULL)
+ vsfr->rg_data[vsfr->bufSize - 1] = '\0';
+ dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
+ vsfr->rg_data);
+ }
+ }
+}
+
+static void venus_hfi_flush_debug_queue(
+ struct venus_hfi_device *device, u8 *packet)
+{
+ bool local_packet = false;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+ return;
+ }
+ if (!packet) {
+ packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+ if (!packet) {
+ dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n",
+ __func__);
+ return;
+ }
+ local_packet = true;
+ }
+
+ while (!venus_hfi_iface_dbgq_read(device, packet)) {
+ struct hfi_msg_sys_coverage_packet *pkt =
+ (struct hfi_msg_sys_coverage_packet *) packet;
+ if (pkt->packet_type == HFI_MSG_SYS_COV) {
+#ifdef CONFIG_MSM_VIDC_COV
+ int stm_size = 0;
+ dprintk(VIDC_DBG,
+ "DbgQ pkt size: %d\n", pkt->msg_size);
+ stm_size = stm_log_inv_ts(0, 0,
+ pkt->rg_msg_data, pkt->msg_size);
+ if (stm_size == 0)
+ dprintk(VIDC_ERR,
+ "In %s, stm_log returned size of 0\n",
+ __func__);
+#endif
+ } else {
+ struct hfi_msg_sys_debug_packet *pkt =
+ (struct hfi_msg_sys_debug_packet *) packet;
+ dprintk(VIDC_FW, "%s", pkt->rg_msg_data);
+ }
+ }
+ if (local_packet)
+ kfree(packet);
+}
+
+static void venus_hfi_response_handler(struct venus_hfi_device *device)
+{
+ u8 *packet = NULL;
+ u32 rc = 0;
+ struct hfi_sfr_struct *vsfr = NULL;
+
+ packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+ if (!packet) {
+ dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n", __func__);
+ return;
+ }
+ dprintk(VIDC_INFO, "#####venus_hfi_response_handler#####\n");
+ if (device) {
+ if (device->intr_status &
+ VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) {
+ dprintk(VIDC_ERR, "Received: Watchdog timeout %s\n",
+ __func__);
+ vsfr = (struct hfi_sfr_struct *)
+ device->sfr.align_virtual_addr;
+ if (vsfr)
+ dprintk(VIDC_ERR,
+ "SFR Message from FW: %s\n",
+ vsfr->rg_data);
+ venus_hfi_process_sys_watchdog_timeout(device);
+ }
+
+ while (!venus_hfi_iface_msgq_read(device, packet)) {
+ rc = hfi_process_msg_packet(device->callback,
+ device->device_id,
+ (struct vidc_hal_msg_pkt_hdr *) packet,
+ &device->sess_head, &device->session_lock);
+ if (rc == HFI_MSG_EVENT_NOTIFY) {
+ venus_hfi_process_msg_event_notify(
+ device, (void *)packet);
+ } else if (rc == HFI_MSG_SYS_RELEASE_RESOURCE) {
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_RELEASE_RESOURCE\n");
+ complete(&release_resources_done);
+ } else if (rc == HFI_MSG_SYS_INIT_DONE) {
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_INIT_DONE\n");
+ if (venus_hfi_alloc_set_imem(device, true))
+ dprintk(VIDC_WARN,
+ "Failed to allocate IMEM. Performance will be impacted\n");
+ }
+ }
+ venus_hfi_flush_debug_queue(device, packet);
+ switch (rc) {
+ case HFI_MSG_SYS_PC_PREP_DONE:
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_PC_PREP_DONE\n");
+ complete(&pc_prep_done);
+ break;
+ }
+ } else {
+ dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT\n");
+ }
+ kfree(packet);
+}
+
+static void venus_hfi_core_work_handler(struct work_struct *work)
+{
+ struct venus_hfi_device *device = list_first_entry(
+ &hal_ctxt.dev_head, struct venus_hfi_device, list);
+
+ dprintk(VIDC_INFO, "GOT INTERRUPT\n");
+ if (!device->callback) {
+ dprintk(VIDC_ERR, "No interrupt callback function: %p\n",
+ device);
+ return;
+ }
+ if (venus_hfi_power_enable(device)) {
+ dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__);
+ return;
+ }
+ if (device->res->sw_power_collapsible) {
+ dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n");
+ cancel_delayed_work(&venus_hfi_pm_work);
+ if (!queue_delayed_work(device->venus_pm_workq,
+ &venus_hfi_pm_work,
+ msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
+ dprintk(VIDC_DBG, "PM work already scheduled\n");
+ }
+ }
+ venus_hfi_core_clear_interrupt(device);
+ venus_hfi_response_handler(device);
+ if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+ enable_irq(device->hal_data->irq);
+}
+static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
+
+static irqreturn_t venus_hfi_isr(int irq, void *dev)
+{
+ struct venus_hfi_device *device = dev;
+ dprintk(VIDC_INFO, "vidc_hal_isr %d\n", irq);
+ disable_irq_nosync(irq);
+ queue_work(device->vidc_workq, &venus_hfi_work);
+ return IRQ_HANDLED;
+}
+
+static int venus_hfi_init_regs_and_interrupts(
+ struct venus_hfi_device *device,
+ struct msm_vidc_platform_resources *res)
+{
+ struct hal_data *hal = NULL;
+ int rc = 0;
+
+ rc = venus_hfi_check_core_registered(hal_ctxt,
+ res->firmware_base,
+ (u8 *)(unsigned long)res->register_base,
+ res->register_size, res->irq);
+ if (!rc) {
+ dprintk(VIDC_ERR, "Core present/Already added\n");
+ rc = -EEXIST;
+ goto err_core_init;
+ }
+
+ dprintk(VIDC_DBG, "HAL_DATA will be assigned now\n");
+ hal = (struct hal_data *)
+ kzalloc(sizeof(struct hal_data), GFP_KERNEL);
+ if (!hal) {
+ dprintk(VIDC_ERR, "Failed to alloc\n");
+ rc = -ENOMEM;
+ goto err_core_init;
+ }
+ hal->irq = res->irq;
+ hal->firmware_base = res->firmware_base;
+ hal->register_base = ioremap_nocache(res->register_base,
+ (unsigned long)res->register_size);
+ hal->register_size = res->register_size;
+ if (!hal->register_base) {
+ dprintk(VIDC_ERR,
+ "could not map reg addr %pa of size %d\n",
+ &res->register_base, res->register_size);
+ goto error_irq_fail;
+ }
+
+ device->hal_data = hal;
+ rc = request_irq(res->irq, venus_hfi_isr, IRQF_TRIGGER_HIGH,
+ "msm_vidc", device);
+ if (unlikely(rc)) {
+ dprintk(VIDC_ERR, "() :request_irq failed\n");
+ goto error_irq_fail;
+ }
+ disable_irq_nosync(res->irq);
+ dprintk(VIDC_INFO,
+ "firmware_base = %pa, register_base = %pa, register_size = %d\n",
+ &res->firmware_base, &res->register_base,
+ res->register_size);
+ return rc;
+
+error_irq_fail:
+ kfree(hal);
+err_core_init:
+ return rc;
+
+}
+
+static inline void venus_hfi_deinit_clocks(struct venus_hfi_device *device)
+{
+ struct clock_info *cl;
+
+ venus_hfi_for_each_clock_reverse(device, cl) {
+ if (cl->clk) {
+ clk_put(cl->clk);
+ cl->clk = NULL;
+ }
+ }
+}
+
+static inline int venus_hfi_init_clocks(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ struct clock_info *cl = NULL;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+
+ venus_hfi_for_each_clock(device, cl) {
+ int i = 0;
+
+ dprintk(VIDC_DBG, "%s: scalable? %d\n",
+ cl->name, !!cl->count);
+ for (i = 0; i < cl->count; ++i) {
+ dprintk(VIDC_DBG,
+ "\tload = %d, freq = %d codecs supported %#x\n",
+ cl->load_freq_tbl[i].load,
+ cl->load_freq_tbl[i].freq,
+ cl->load_freq_tbl[i].supported_codecs);
+ }
+ }
+
+ venus_hfi_for_each_clock(device, cl) {
+ if (!cl->clk) {
+ cl->clk = clk_get(&device->res->pdev->dev, cl->name);
+ if (IS_ERR_OR_NULL(cl->clk)) {
+ dprintk(VIDC_ERR,
+ "Failed to get clock: %s\n", cl->name);
+ rc = PTR_ERR(cl->clk) ?: -EINVAL;
+ cl->clk = NULL;
+ goto err_clk_get;
+ }
+ }
+ }
+
+ return 0;
+
+err_clk_get:
+ venus_hfi_deinit_clocks(device);
+ return rc;
+}
+
+
+static inline void venus_hfi_disable_unprepare_clks(
+ struct venus_hfi_device *device)
+{
+ struct clock_info *cl;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+
+ if (device->clk_state == DISABLED_UNPREPARED) {
+ dprintk(VIDC_DBG, "Clocks already unprepared and disabled\n");
+ return;
+ }
+
+ /*
+ * Make the clock state variable as unprepared before actually
+ * unpreparing clocks. This will make sure that when we check
+ * the state, we have the right clock state. We are not taking
+ * any action based unprepare failures. So it is safe to do
+ * before the call. This is also in sync with prepare_enable
+ * state update.
+ */
+
+ device->clk_state = DISABLED_UNPREPARED;
+
+ venus_hfi_for_each_clock(device, cl) {
+ usleep_range(100, 500);
+ dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n",
+ cl->name);
+ clk_disable_unprepare(cl->clk);
+ }
+}
+
+static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device)
+{
+ struct clock_info *cl = NULL, *cl_fail = NULL;
+ int rc = 0;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+
+ if (device->clk_state == ENABLED_PREPARED) {
+ dprintk(VIDC_DBG, "Clocks already prepared and enabled\n");
+ return 0;
+ }
+
+ venus_hfi_for_each_clock(device, cl) {
+ /*
+ * For the clocks we control, set the rate prior to preparing
+ * them. Since we don't really have a load at this point, scale
+ * it to the lowest frequency possible
+ */
+ if (cl->count)
+ clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
+
+ rc = clk_prepare_enable(cl->clk);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to enable clock %s, %d\n", cl->name, rc);
+ cl_fail = cl;
+ goto fail_clk_enable;
+ }
+
+ dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name);
+ }
+
+ device->clk_state = ENABLED_PREPARED;
+ venus_hfi_write_register(device, VIDC_WRAPPER_CLOCK_CONFIG, 0);
+ venus_hfi_write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0);
+ return rc;
+
+fail_clk_enable:
+ venus_hfi_for_each_clock(device, cl) {
+ if (cl_fail == cl)
+ break;
+ usleep_range(100, 500);
+ dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n",
+ cl->name);
+ clk_disable_unprepare(cl->clk);
+ }
+ device->clk_state = DISABLED_UNPREPARED;
+ return rc;
+}
+
+static void venus_hfi_deinit_bus(struct venus_hfi_device *device)
+{
+ struct bus_info *bus = NULL;
+ if (!device)
+ return;
+
+ venus_hfi_for_each_bus(device, bus) {
+ if (bus->priv) {
+ msm_bus_scale_unregister_client(
+ bus->priv);
+ bus->priv = 0;
+ dprintk(VIDC_DBG, "Unregistered bus client %s\n",
+ bus->pdata->name);
+ }
+ }
+
+ kfree(device->bus_load.vote_data);
+ device->bus_load.vote_data = NULL;
+ device->bus_load.vote_data_count = 0;
+}
+
+static int venus_hfi_init_bus(struct venus_hfi_device *device)
+{
+ struct bus_info *bus = NULL;
+ int rc = 0;
+ if (!device)
+ return -EINVAL;
+
+
+ venus_hfi_for_each_bus(device, bus) {
+ const char *name = bus->pdata->name;
+
+ if (!device->res->imem_type &&
+ strnstr(name, "ocmem", strlen(name))) {
+ dprintk(VIDC_ERR,
+ "%s found when target doesn't support ocmem\n",
+ name);
+ rc = -EINVAL;
+ goto err_init_bus;
+ } else if (bus->passive && bus->pdata->num_usecases != 2) {
+ /*
+ * Passive buses can only be "turned on" and "turned
+ * off". We never scale them based on hardware load,
+ * and are usually used for the purposes of holding
+ * certain clocks high (in case we can't control these
+ * clocks directly).
+ */
+ rc = -EINVAL;
+ dprintk(VIDC_ERR,
+ "Passive buses expected to have only 2 vectors\n");
+ }
+
+ bus->priv = msm_bus_scale_register_client(bus->pdata);
+ if (!bus->priv) {
+ dprintk(VIDC_ERR,
+ "Failed to register bus client %s\n", name);
+ rc = -EBADHANDLE;
+ goto err_init_bus;
+ }
+
+ dprintk(VIDC_DBG, "Registered bus client %s\n", name);
+ }
+
+ device->bus_load.vote_data = NULL;
+ device->bus_load.vote_data_count = 0;
+
+ return rc;
+err_init_bus:
+ venus_hfi_deinit_bus(device);
+ return rc;
+}
+
+static void venus_hfi_deinit_regulators(struct venus_hfi_device *device)
+{
+ struct regulator_info *rinfo = NULL;
+
+ venus_hfi_for_each_regulator_reverse(device, rinfo) {
+ if (rinfo->regulator) {
+ regulator_put(rinfo->regulator);
+ rinfo->regulator = NULL;
+ }
+ }
+}
+
+static int venus_hfi_init_regulators(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ struct regulator_info *rinfo = NULL;
+
+ venus_hfi_for_each_regulator(device, rinfo) {
+ rinfo->regulator = regulator_get(&device->res->pdev->dev,
+ rinfo->name);
+ if (IS_ERR_OR_NULL(rinfo->regulator)) {
+ rc = PTR_ERR(rinfo->regulator) ?: -EBADHANDLE;
+ dprintk(VIDC_ERR, "Failed to get regulator: %s, err: %d\n",
+ rinfo->name, rc);
+ rinfo->regulator = NULL;
+ goto err_reg_get;
+ }
+ }
+
+ return 0;
+
+err_reg_get:
+ venus_hfi_deinit_regulators(device);
+ return rc;
+}
+
+static int venus_hfi_init_resources(struct venus_hfi_device *device,
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+
+#if 0
+ rc = venus_hfi_init_regulators(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get all regulators\n");
+ return -ENODEV;
+ }
+#endif
+
+ rc = venus_hfi_init_clocks(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to init clocks\n");
+ rc = -ENODEV;
+ goto err_init_clocks;
+ }
+
+ rc = venus_hfi_init_bus(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to init bus: %d\n", rc);
+ goto err_init_bus;
+ }
+
+ return rc;
+
+err_init_bus:
+ venus_hfi_deinit_clocks(device);
+err_init_clocks:
+ venus_hfi_deinit_regulators(device);
+ return rc;
+}
+
+static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
+{
+ venus_hfi_deinit_bus(device);
+ venus_hfi_deinit_clocks(device);
+ venus_hfi_deinit_regulators(device);
+}
+
+static int protect_cp_mem(struct venus_hfi_device *device)
+{
+ u32 cp_start = 0;
+ u32 cp_size = 0;
+ u32 cp_nonpixel_start = 0;
+ u32 cp_nonpixel_size = 0;
+ struct context_bank_info *cb;
+ int ret;
+
+ if (!device)
+ return -EINVAL;
+
+ list_for_each_entry(cb, &device->res->context_banks, list) {
+ if (!strcmp(cb->name, "venus_ns")) {
+ cp_size = cb->addr_range.start;
+ dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n",
+ __func__, cp_size);
+ }
+
+ if (!strcmp(cb->name, "venus_sec_non_pixel")) {
+ cp_nonpixel_start = cb->addr_range.start;
+ cp_nonpixel_size = cb->addr_range.size;
+ dprintk(VIDC_DBG,
+ "%s memprot.cp_start: %#x size: %#x\n",
+ __func__, cp_nonpixel_start,
+ cp_nonpixel_size);
+ }
+ }
+
+ ret = qcom_scm_mem_protect_video_var(cp_start, cp_size,
+ cp_nonpixel_start,
+ cp_nonpixel_size);
+ if (ret) {
+ dprintk(VIDC_ERR, "Failed to protect memory (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int venus_hfi_disable_regulator(struct regulator_info *rinfo)
+{
+ int rc = 0;
+
+ dprintk(VIDC_DBG, "Disabling regulator %s\n", rinfo->name);
+
+ /*
+ * This call is needed. Driver needs to acquire the control back
+ * from HW in order to disable the regualtor. Else the behavior
+ * is unknown.
+ */
+
+ rc = venus_hfi_acquire_regulator(rinfo);
+
+ if (rc) {
+ /* This is somewhat fatal, but nothing we can do
+ * about it. We can't disable the regulator w/o
+ * getting it back under s/w control */
+ dprintk(VIDC_WARN,
+ "Failed to acquire control on %s\n",
+ rinfo->name);
+
+ goto disable_regulator_failed;
+ }
+ rc = regulator_disable(rinfo->regulator);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to disable %s: %d\n",
+ rinfo->name, rc);
+ goto disable_regulator_failed;
+ }
+
+ return 0;
+disable_regulator_failed:
+
+ /* Bring attention to this issue */
+ WARN_ON(1);
+ return rc;
+}
+
+static int venus_hfi_enable_hw_power_collapse(struct venus_hfi_device *device)
+{
+ int rc = 0;
+
+ if (!msm_vidc_fw_low_power_mode) {
+ dprintk(VIDC_DBG, "Not enabling hardware power collapse\n");
+ return 0;
+ }
+
+ rc = venus_hfi_hand_off_regulators(device);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "%s : Failed to enable HW power collapse %d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int venus_hfi_enable_regulators(struct venus_hfi_device *device)
+{
+ int rc = 0, c = 0;
+ struct regulator_info *rinfo;
+
+ dprintk(VIDC_DBG, "Enabling regulators\n");
+
+ venus_hfi_for_each_regulator(device, rinfo) {
+ rc = regulator_enable(rinfo->regulator);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to enable %s: %d\n",
+ rinfo->name, rc);
+ goto err_reg_enable_failed;
+ }
+ dprintk(VIDC_DBG, "Enabled regulator %s\n",
+ rinfo->name);
+ c++;
+ }
+
+ return 0;
+
+err_reg_enable_failed:
+ venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+ venus_hfi_disable_regulator(rinfo);
+
+ return rc;
+}
+
+static int venus_hfi_disable_regulators(struct venus_hfi_device *device)
+{
+ struct regulator_info *rinfo;
+
+ dprintk(VIDC_DBG, "Disabling regulators\n");
+
+ venus_hfi_for_each_regulator_reverse(device, rinfo)
+ venus_hfi_disable_regulator(rinfo);
+
+ return 0;
+}
+
+static int venus_hfi_load_fw(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ /* Initialize hardware resources */
+ rc = venus_hfi_init_resources(device, device->res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+ goto fail_init_res;
+ }
+
+ rc = venus_hfi_initialize_packetization(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to initialize packetization\n");
+ goto fail_init_pkt;
+ }
+ trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc venus_fw load start");
+
+ /* Vote for all hardware resources */
+ rc = venus_hfi_vote_buses(device, device->bus_load.vote_data,
+ device->bus_load.vote_data_count);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to vote buses when loading firmware: %d\n",
+ rc);
+ goto fail_vote_buses;
+ }
+
+#if 0
+ rc = venus_hfi_enable_regulators(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s : Failed to enable GDSC, Err = %d\n",
+ __func__, rc);
+ goto fail_enable_gdsc;
+ }
+#endif
+
+ /* iommu_attach makes call to TZ for restore_sec_cfg. With this call
+ * TZ accesses the VMIDMT block which needs all the Venus clocks.
+ */
+ rc = venus_hfi_prepare_enable_clks(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
+ goto fail_enable_clks;
+ }
+
+ if ((!device->res->use_non_secure_pil && !device->res->firmware_base)
+ || device->res->use_non_secure_pil) {
+
+ if (!device->resources.fw.cookie)
+ device->resources.fw.cookie =
+#if 0
+ subsystem_get_with_fwname("venus",
+ device->res->fw_name);
+#else
+ subsystem_get("venus");
+#endif
+
+ if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
+ dprintk(VIDC_ERR, "Failed to download firmware\n");
+ rc = -ENOMEM;
+ goto fail_load_fw;
+ }
+ }
+ device->power_enabled = true;
+
+ /* Hand off control of regulators to h/w _after_ enabling clocks */
+ venus_hfi_enable_hw_power_collapse(device);
+
+ if (!device->res->use_non_secure_pil && !device->res->firmware_base) {
+#if 0
+ rc = protect_cp_mem(device);
+#else
+ rc = 0;
+#endif
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to protect memory\n");
+ goto fail_protect_mem;
+ }
+ }
+
+ trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+ return rc;
+fail_protect_mem:
+ device->power_enabled = false;
+ if (device->resources.fw.cookie)
+ subsystem_put(device->resources.fw.cookie);
+ device->resources.fw.cookie = NULL;
+fail_load_fw:
+ venus_hfi_disable_unprepare_clks(device);
+fail_enable_clks:
+ venus_hfi_disable_regulators(device);
+fail_enable_gdsc:
+ venus_hfi_unvote_buses(device);
+fail_vote_buses:
+fail_init_pkt:
+ venus_hfi_deinit_resources(device);
+fail_init_res:
+ trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+ return rc;
+}
+
+static void venus_hfi_unload_fw(void *dev)
+{
+ struct venus_hfi_device *device = dev;
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return;
+ }
+ if (device->resources.fw.cookie) {
+ flush_workqueue(device->vidc_workq);
+ cancel_delayed_work(&venus_hfi_pm_work);
+ flush_workqueue(device->venus_pm_workq);
+ subsystem_put(device->resources.fw.cookie);
+ venus_hfi_interface_queues_release(dev);
+
+ /* Halt the AXI to make sure there are no pending transactions.
+ * Clocks should be unprepared after making sure axi is halted.
+ */
+ if (venus_hfi_halt_axi(device))
+ dprintk(VIDC_WARN, "Failed to halt AXI\n");
+ venus_hfi_disable_unprepare_clks(device);
+#if 0
+ venus_hfi_disable_regulators(device);
+#endif
+ venus_hfi_unvote_buses(device);
+ device->power_enabled = false;
+ device->resources.fw.cookie = NULL;
+ }
+}
+
+static int venus_hfi_resurrect_fw(void *dev)
+{
+ struct venus_hfi_device *device = dev;
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ rc = venus_hfi_core_release(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to release venus core rc = %d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ dprintk(VIDC_ERR, "praying for firmware resurrection\n");
+ venus_hfi_unload_fw(device);
+
+ rc = venus_hfi_vote_buses(device, device->bus_load.vote_data,
+ device->bus_load.vote_data_count);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale buses\n");
+ goto exit;
+ }
+
+ rc = venus_hfi_load_fw(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to load venus fw rc = %d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ dprintk(VIDC_ERR, "Hurray!! firmware has restarted\n");
+exit:
+ return rc;
+}
+
+static int venus_hfi_get_fw_info(void *dev, enum fw_info info)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ switch (info) {
+ case FW_BASE_ADDRESS:
+ rc = (u32)device->hal_data->firmware_base;
+ if ((phys_addr_t)rc != device->hal_data->firmware_base) {
+ dprintk(VIDC_INFO,
+ "%s: firmware_base (%pa) truncated to %#x",
+ __func__, &device->hal_data->firmware_base, rc);
+ }
+ break;
+
+ case FW_REGISTER_BASE:
+ rc = (u32)device->res->register_base;
+ if ((phys_addr_t)rc != device->res->register_base) {
+ dprintk(VIDC_INFO,
+ "%s: register_base (%pa) truncated to %#x",
+ __func__, &device->res->register_base, rc);
+ }
+ break;
+
+ case FW_REGISTER_SIZE:
+ rc = device->hal_data->register_size;
+ break;
+
+ case FW_IRQ:
+ rc = device->hal_data->irq;
+ break;
+
+ default:
+ dprintk(VIDC_ERR, "Invalid fw info requested\n");
+ }
+ return rc;
+}
+
+int venus_hfi_get_stride_scanline(int color_fmt,
+ int width, int height, int *stride, int *scanlines) {
+ *stride = VENUS_Y_STRIDE(color_fmt, width);
+ *scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+ return 0;
+}
+
+int venus_hfi_get_core_capabilities(void)
+{
+ int rc = 0;
+ rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
+ HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
+ HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
+ HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
+ return rc;
+}
+
+static int venus_hfi_initialize_packetization(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ const char *hfi_version;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ hfi_version = device->res->hfi_version;
+
+ if (!hfi_version) {
+ device->packetization_type = HFI_PACKETIZATION_LEGACY;
+ } else if (!strcmp(hfi_version, "3xx")) {
+ device->packetization_type = HFI_PACKETIZATION_3XX;
+ } else {
+ dprintk(VIDC_ERR, "Unsupported hfi version\n");
+ return -EINVAL;
+ }
+
+ device->pkt_ops = hfi_get_pkt_ops_handle(device->packetization_type);
+ if (!device->pkt_ops) {
+ rc = -EINVAL;
+ dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n");
+ }
+
+ return rc;
+}
+
+static void *venus_hfi_add_device(u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ struct venus_hfi_device *hdevice = NULL;
+ int rc = 0;
+
+ if (!res || !callback) {
+ dprintk(VIDC_ERR, "Invalid Parameters\n");
+ return NULL;
+ }
+
+ dprintk(VIDC_INFO, "entered , device_id: %d\n", device_id);
+
+ hdevice = (struct venus_hfi_device *)
+ kzalloc(sizeof(struct venus_hfi_device), GFP_KERNEL);
+ if (!hdevice) {
+ dprintk(VIDC_ERR, "failed to allocate new device\n");
+ goto err_alloc;
+ }
+
+ rc = venus_hfi_init_regs_and_interrupts(hdevice, res);
+ if (rc)
+ goto err_init_regs;
+
+ hdevice->res = res;
+ hdevice->device_id = device_id;
+ hdevice->callback = callback;
+
+ hdevice->vidc_workq = create_singlethread_workqueue(
+ "msm_vidc_workerq_venus");
+ if (!hdevice->vidc_workq) {
+ dprintk(VIDC_ERR, ": create vidc workq failed\n");
+ goto error_createq;
+ }
+ hdevice->venus_pm_workq = create_singlethread_workqueue(
+ "pm_workerq_venus");
+ if (!hdevice->venus_pm_workq) {
+ dprintk(VIDC_ERR, ": create pm workq failed\n");
+ goto error_createq_pm;
+ }
+
+ mutex_init(&hdevice->read_lock);
+ mutex_init(&hdevice->write_lock);
+ mutex_init(&hdevice->session_lock);
+ mutex_init(&hdevice->resource_lock);
+
+ if (!hal_ctxt.dev_count)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
+ INIT_LIST_HEAD(&hdevice->sess_head);
+ list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+ hal_ctxt.dev_count++;
+
+ return (void *) hdevice;
+error_createq_pm:
+ destroy_workqueue(hdevice->vidc_workq);
+error_createq:
+err_init_regs:
+ kfree(hdevice);
+err_alloc:
+ return NULL;
+}
+
+static void *venus_hfi_get_device(u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ if (!res || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p\n", res, callback);
+ return NULL;
+ }
+
+ return venus_hfi_add_device(device_id, res, callback);
+}
+
+void venus_hfi_delete_device(void *device)
+{
+ struct venus_hfi_device *close, *tmp, *dev;
+
+ if (device) {
+ venus_hfi_iommu_detach(device);
+ venus_hfi_deinit_resources(device);
+ dev = (struct venus_hfi_device *) device;
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
+ if (close->hal_data->irq == dev->hal_data->irq) {
+ hal_ctxt.dev_count--;
+ list_del(&close->list);
+ destroy_workqueue(close->vidc_workq);
+ destroy_workqueue(close->venus_pm_workq);
+ free_irq(dev->hal_data->irq, close);
+ iounmap(dev->hal_data->register_base);
+ kfree(close->hal_data);
+ kfree(close);
+ break;
+ }
+ }
+
+ }
+}
+
+static void venus_init_hfi_callbacks(struct hfi_device *hdev)
+{
+ hdev->core_init = venus_hfi_core_init;
+ hdev->core_release = venus_hfi_core_release;
+ hdev->core_pc_prep = venus_hfi_core_pc_prep;
+ hdev->core_ping = venus_hfi_core_ping;
+ hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
+ hdev->session_init = venus_hfi_session_init;
+ hdev->session_end = venus_hfi_session_end;
+ hdev->session_abort = venus_hfi_session_abort;
+ hdev->session_clean = venus_hfi_session_clean;
+ hdev->session_set_buffers = venus_hfi_session_set_buffers;
+ hdev->session_release_buffers = venus_hfi_session_release_buffers;
+ hdev->session_load_res = venus_hfi_session_load_res;
+ hdev->session_release_res = venus_hfi_session_release_res;
+ hdev->session_start = venus_hfi_session_start;
+ hdev->session_stop = venus_hfi_session_stop;
+ hdev->session_etb = venus_hfi_session_etb;
+ hdev->session_ftb = venus_hfi_session_ftb;
+ hdev->session_parse_seq_hdr = venus_hfi_session_parse_seq_hdr;
+ hdev->session_get_seq_hdr = venus_hfi_session_get_seq_hdr;
+ hdev->session_get_buf_req = venus_hfi_session_get_buf_req;
+ hdev->session_flush = venus_hfi_session_flush;
+ hdev->session_set_property = venus_hfi_session_set_property;
+ hdev->session_get_property = venus_hfi_session_get_property;
+ hdev->scale_clocks = venus_hfi_scale_clocks;
+ hdev->vote_bus = venus_hfi_vote_active_buses;
+ hdev->unvote_bus = venus_hfi_unvote_active_buses;
+ hdev->load_fw = venus_hfi_load_fw;
+ hdev->unload_fw = venus_hfi_unload_fw;
+ hdev->resurrect_fw = venus_hfi_resurrect_fw;
+ hdev->get_fw_info = venus_hfi_get_fw_info;
+ hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
+ hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+ hdev->power_enable = venus_hfi_power_enable;
+ hdev->suspend = venus_hfi_suspend;
+ hdev->get_core_clock_rate = venus_hfi_get_core_clock_rate;
+ hdev->get_default_properties = venus_hfi_get_default_properties;
+}
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ int rc = 0;
+
+ if (!hdev || !res || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p %p\n",
+ hdev, res, callback);
+ rc = -EINVAL;
+ goto err_venus_hfi_init;
+ }
+ hdev->hfi_device_data = venus_hfi_get_device(device_id, res, callback);
+
+ if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+ rc = PTR_ERR(hdev->hfi_device_data) ?: -EINVAL;
+ goto err_venus_hfi_init;
+ }
+
+ venus_init_hfi_callbacks(hdev);
+
+err_venus_hfi_init:
+ return rc;
+}
+
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
new file mode 100644
index 000000000000..2ae40db73b99
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -0,0 +1,280 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+
+#ifndef __H_VENUS_HFI_H__
+#define __H_VENUS_HFI_H__
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <soc/qcom/ocmem.h>
+#include "vmem/vmem.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi.h"
+#include "msm_vidc_resources.h"
+#include "hfi_packetization.h"
+
+#define HFI_MASK_QHDR_TX_TYPE 0xFF000000
+#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000
+#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00
+#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF
+#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q 0x00
+#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q 0x01
+#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q 0x02
+#define HFI_MASK_QHDR_STATUS 0x000000FF
+
+#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES 3
+
+#define VIDC_IFACEQ_NUMQ 3
+#define VIDC_IFACEQ_CMDQ_IDX 0
+#define VIDC_IFACEQ_MSGQ_IDX 1
+#define VIDC_IFACEQ_DBGQ_IDX 2
+#define VIDC_IFACEQ_MAX_BUF_COUNT 50
+#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16
+#define VIDC_IFACEQ_DFLT_QHDR 0x01010000
+
+#define VIDC_MAX_NAME_LENGTH 64
+
+struct hfi_queue_table_header {
+ u32 qtbl_version;
+ u32 qtbl_size;
+ u32 qtbl_qhdr0_offset;
+ u32 qtbl_qhdr_size;
+ u32 qtbl_num_q;
+ u32 qtbl_num_active_q;
+};
+
+struct hfi_queue_header {
+ u32 qhdr_status;
+ u32 qhdr_start_addr;
+ u32 qhdr_type;
+ u32 qhdr_q_size;
+ u32 qhdr_pkt_size;
+ u32 qhdr_pkt_drop_cnt;
+ u32 qhdr_rx_wm;
+ u32 qhdr_tx_wm;
+ u32 qhdr_rx_req;
+ u32 qhdr_tx_req;
+ u32 qhdr_rx_irq_status;
+ u32 qhdr_tx_irq_status;
+ u32 qhdr_read_idx;
+ u32 qhdr_write_idx;
+};
+
+struct hfi_mem_map_table {
+ u32 mem_map_num_entries;
+ u32 mem_map_table_base_addr;
+};
+
+struct hfi_mem_map {
+ u32 virtual_addr;
+ u32 physical_addr;
+ u32 size;
+ u32 attr;
+};
+
+#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+ + sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
+
+#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
+ VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
+
+#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
+ (void *)((ptr + sizeof(struct hfi_queue_table_header)) + \
+ (i * sizeof(struct hfi_queue_header)))
+
+#define QDSS_SIZE 4096
+#define SFR_SIZE 4096
+
+#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
+ (VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ))
+
+#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K)
+#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K)
+#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K)
+#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \
+ ALIGNED_QDSS_SIZE, SZ_1M)
+
+enum vidc_hw_reg {
+ VIDC_HWREG_CTRL_STATUS = 0x1,
+ VIDC_HWREG_QTBL_INFO = 0x2,
+ VIDC_HWREG_QTBL_ADDR = 0x3,
+ VIDC_HWREG_CTRLR_RESET = 0x4,
+ VIDC_HWREG_IFACEQ_FWRXREQ = 0x5,
+ VIDC_HWREG_IFACEQ_FWTXREQ = 0x6,
+ VIDC_HWREG_VHI_SOFTINTEN = 0x7,
+ VIDC_HWREG_VHI_SOFTINTSTATUS = 0x8,
+ VIDC_HWREG_VHI_SOFTINTCLR = 0x9,
+ VIDC_HWREG_HVI_SOFTINTEN = 0xA,
+};
+
+enum bus_index {
+ BUS_IDX_ENC_IMEM,
+ BUS_IDX_DEC_IMEM,
+ BUS_IDX_ENC_DDR,
+ BUS_IDX_DEC_DDR,
+ BUS_IDX_MAX
+};
+
+enum clock_state {
+ DISABLED_UNPREPARED,
+ ENABLED_PREPARED,
+};
+
+struct vidc_mem_addr {
+ ion_phys_addr_t align_device_addr;
+ u8 *align_virtual_addr;
+ u32 mem_size;
+ struct msm_smem *mem_data;
+};
+
+struct vidc_iface_q_info {
+ void *q_hdr;
+ struct vidc_mem_addr q_array;
+};
+
+/*
+ * These are helper macros to iterate over various lists within
+ * venus_hfi_device->res. The intention is to cut down on a lot of boiler-plate
+ * code
+ */
+
+/* Read as "for each 'thing' in a set of 'thingies'" */
+#define venus_hfi_for_each_thing(__device, __thing, __thingy) \
+ venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0)
+
+#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \
+ venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+ (__device)->res->__thingy##_set.count - 1)
+
+/* TODO: the __from parameter technically not required since we can figure it
+ * out with some pointer magic (i.e. __thing - __thing##_tbl[0]). If this macro
+ * sees extensive use, probably worth cleaning it up but for now omitting it
+ * since it introduces unneccessary complexity.
+ */
+#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \
+ for (__thing = &(__device)->res->\
+ __thingy##_set.__thingy##_tbl[__from]; \
+ __thing < &(__device)->res->__thingy##_set.__thingy##_tbl[0] + \
+ ((__device)->res->__thingy##_set.count - __from); \
+ ++__thing)
+
+#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+ __from) \
+ for (__thing = &(__device)->res->\
+ __thingy##_set.__thingy##_tbl[__from]; \
+ __thing >= &(__device)->res->__thingy##_set.__thingy##_tbl[0]; \
+ --__thing)
+
+/* Regular set helpers */
+#define venus_hfi_for_each_regulator(__device, __rinfo) \
+ venus_hfi_for_each_thing(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \
+ venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \
+ __from) \
+ venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
+ regulator, __from)
+
+/* Clock set helpers */
+#define venus_hfi_for_each_clock(__device, __cinfo) \
+ venus_hfi_for_each_thing(__device, __cinfo, clock)
+
+#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \
+ venus_hfi_for_each_thing_reverse(__device, __cinfo, clock)
+
+/* Bus set helpers */
+#define venus_hfi_for_each_bus(__device, __binfo) \
+ venus_hfi_for_each_thing(__device, __binfo, bus)
+
+
+/* Internal data used in vidc_hal not exposed to msm_vidc*/
+struct hal_data {
+ u32 irq;
+ phys_addr_t firmware_base;
+ u8 __iomem *register_base;
+ u32 register_size;
+};
+
+struct on_chip_mem {
+ struct ocmem_buf *buf;
+ struct notifier_block vidc_ocmem_nb;
+ void *handle;
+};
+
+struct imem {
+ enum imem_type type;
+ union {
+ struct on_chip_mem ocmem;
+ phys_addr_t vmem;
+ };
+};
+
+struct venus_resources {
+ struct msm_vidc_fw fw;
+ struct imem imem;
+};
+
+enum venus_hfi_state {
+ VENUS_STATE_DEINIT = 1,
+ VENUS_STATE_INIT,
+};
+
+struct venus_hfi_device {
+ struct list_head list;
+ struct list_head sess_head;
+ u32 intr_status;
+ u32 device_id;
+ u32 clk_load;
+ u32 codecs_enabled;
+ u32 last_packet_type;
+ struct {
+ struct vidc_bus_vote_data *vote_data;
+ u32 vote_data_count;
+ } bus_load;
+ enum clock_state clk_state;
+ bool power_enabled;
+ struct mutex read_lock;
+ struct mutex write_lock;
+ struct mutex resource_lock;
+ struct mutex session_lock;
+ msm_vidc_callback callback;
+ struct vidc_mem_addr iface_q_table;
+ struct vidc_mem_addr qdss;
+ struct vidc_mem_addr sfr;
+ struct vidc_mem_addr mem_addr;
+ struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
+ struct smem_client *hal_client;
+ struct hal_data *hal_data;
+ struct workqueue_struct *vidc_workq;
+ struct workqueue_struct *venus_pm_workq;
+ int spur_count;
+ int reg_count;
+ struct venus_resources resources;
+ struct msm_vidc_platform_resources *res;
+ enum venus_hfi_state state;
+ struct hfi_packetization_ops *pkt_ops;
+ enum hfi_packetization_type packetization_type;
+};
+
+void venus_hfi_delete_device(void *device);
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback);
+#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.c b/drivers/media/platform/msm/vidc/vidc_hfi.c
new file mode 100644
index 000000000000..ef0de370eb09
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012-2013, 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/slab.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+#include "venus_hfi.h"
+#include "q6_hfi.h"
+
+void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback)
+{
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+ hdev = (struct hfi_device *)
+ kzalloc(sizeof(struct hfi_device), GFP_KERNEL);
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s: failed to allocate hdev\n", __func__);
+ return NULL;
+ }
+
+ switch (hfi_type) {
+ case VIDC_HFI_VENUS:
+ rc = venus_hfi_initialize(hdev, device_id, res, callback);
+ break;
+
+ case VIDC_HFI_Q6:
+ rc = q6_hfi_initialize(hdev, device_id, res, callback);
+ break;
+
+ default:
+ dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+ goto err_hfi_init;
+ }
+
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dprintk(VIDC_ERR, "%s device init failed rc = %d",
+ __func__, rc);
+ goto err_hfi_init;
+ }
+
+ return hdev;
+
+err_hfi_init:
+ kfree(hdev);
+ return ERR_PTR(rc);
+}
+
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+ struct hfi_device *hdev)
+{
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s invalid device %p", __func__, hdev);
+ return;
+ }
+
+ switch (hfi_type) {
+ case VIDC_HFI_VENUS:
+ venus_hfi_delete_device(hdev->hfi_device_data);
+ break;
+
+ case VIDC_HFI_Q6:
+ q6_hfi_delete_device(hdev->hfi_device_data);
+ break;
+
+ default:
+ dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+ }
+ kfree(hdev);
+}
+
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
new file mode 100644
index 000000000000..4b9a9df6431a
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -0,0 +1,890 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+#ifndef __H_VIDC_HFI_H__
+#define __H_VIDC_HFI_H__
+
+#include <media/msm_media_info.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+
+#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
+#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
+
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x1)
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x2)
+
+#define HFI_BUFFERFLAG_EOS 0x00000001
+#define HFI_BUFFERFLAG_STARTTIME 0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HFI_BUFFERFLAG_READONLY 0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HFI_BUFFERFLAG_EOSEQ 0x00200000
+#define HFI_BUFFER_FLAG_MBAFF 0x08000000
+#define HFI_BUFFERFLAG_VPE_YUV_601_709_CSC_CLAMP \
+ 0x10000000
+#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000
+#define HFI_BUFFERFLAG_TEI 0x40000000
+#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000
+
+
+#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \
+ (HFI_OX_BASE + 0x1001)
+#define HFI_ERR_SESSION_SAME_STATE_OPERATION \
+ (HFI_OX_BASE + 0x1002)
+#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \
+ (HFI_OX_BASE + 0x1003)
+#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \
+ (HFI_OX_BASE + 0x1004)
+
+#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
+#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
+
+#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
+
+#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
+#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
+#define HFI_FLUSH_OUTPUT2 (HFI_OX_BASE + 0x3)
+#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
+
+#define HFI_EXTRADATA_NONE 0x00000000
+#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001
+#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002
+#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003
+#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
+#define HFI_EXTRADATA_TIMESTAMP 0x00000005
+#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
+#define HFI_EXTRADATA_FRAME_RATE 0x00000007
+#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008
+#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009
+#define HFI_EXTRADATA_MPEG2_SEQDISP 0x0000000D
+#define HFI_EXTRADATA_STREAM_USERDATA 0x0000000E
+#define HFI_EXTRADATA_FRAME_QP 0x0000000F
+#define HFI_EXTRADATA_FRAME_BITS_INFO 0x00000010
+#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
+#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
+#define HFI_EXTRADATA_INDEX 0x7F100002
+#define HFI_EXTRADATA_METADATA_LTR 0x7F100004
+#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002
+
+#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E
+#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010
+#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
+
+struct hfi_buffer_alloc_mode {
+ u32 buffer_type;
+ u32 buffer_mode;
+};
+
+
+struct hfi_index_extradata_config {
+ int enable;
+ u32 index_extra_data_id;
+};
+
+struct hfi_extradata_header {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 type;
+ u32 data_size;
+ u8 rg_data[1];
+};
+
+#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01
+#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02
+#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04
+#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08
+#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10
+
+#define HFI_PROPERTY_SYS_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+
+#define HFI_PROPERTY_PARAM_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \
+ (HFI_PROPERTY_PARAM_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \
+ (HFI_PROPERTY_PARAM_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_CHROMA_SITE \
+(HFI_PROPERTY_PARAM_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
+ (HFI_PROPERTY_PARAM_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \
+ (HFI_PROPERTY_PARAM_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_DIVX_FORMAT \
+ (HFI_PROPERTY_PARAM_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE \
+ (HFI_PROPERTY_PARAM_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
+ (HFI_PROPERTY_PARAM_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00D)
+
+
+#define HFI_PROPERTY_CONFIG_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
+#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_REALTIME \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_PRIORITY \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_BATCH_INFO \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
+
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
+#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
+#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
+#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019)
+#define HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01A)
+
+#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
+
+#define HFI_PROPERTY_PARAM_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VENC_LTR_INFO \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VENC_MBI_DUMPING \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x005)
+
+#define HFI_PROPERTY_CONFIG_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \
+ (HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
+#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION \
+ (HFI_PROPERTY_PARAM_VPE_OX_START + 0x001)
+
+#define HFI_PROPERTY_CONFIG_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
+
+struct hfi_batch_info {
+ u32 input_batch_count;
+ u32 output_batch_count;
+};
+
+struct hfi_buffer_count_actual {
+ u32 buffer_type;
+ u32 buffer_count_actual;
+};
+
+struct hfi_buffer_size_actual {
+ u32 buffer_type;
+ u32 buffer_size;
+};
+
+struct hfi_buffer_display_hold_count_actual {
+ u32 buffer_type;
+ u32 hold_count;
+};
+
+struct hfi_buffer_requirements {
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 buffer_region_size;
+ u32 buffer_hold_count;
+ u32 buffer_count_min;
+ u32 buffer_count_actual;
+ u32 contiguous;
+ u32 buffer_alignment;
+};
+
+#define HFI_CHROMA_SITE_0 (HFI_OX_BASE + 0x1)
+#define HFI_CHROMA_SITE_1 (HFI_OX_BASE + 0x2)
+#define HFI_CHROMA_SITE_2 (HFI_OX_BASE + 0x3)
+#define HFI_CHROMA_SITE_3 (HFI_OX_BASE + 0x4)
+#define HFI_CHROMA_SITE_4 (HFI_OX_BASE + 0x5)
+#define HFI_CHROMA_SITE_5 (HFI_OX_BASE + 0x6)
+
+struct hfi_data_payload {
+ u32 size;
+ u8 rg_data[1];
+};
+
+struct hfi_enable_picture {
+ u32 picture_type;
+};
+
+struct hfi_display_picture_buffer_count {
+ int enable;
+ u32 count;
+};
+
+struct hfi_extra_data_header_config {
+ u32 type;
+ u32 buffer_type;
+ u32 version;
+ u32 port_index;
+ u32 client_extra_data_id;
+};
+
+struct hfi_interlace_format_supported {
+ u32 buffer_type;
+ u32 format;
+};
+
+struct hfi_buffer_alloc_mode_supported {
+ u32 buffer_type;
+ u32 num_entries;
+ u32 rg_data[1];
+};
+
+struct hfi_mb_error_map {
+ u32 error_map_size;
+ u8 rg_error_map[1];
+};
+
+struct hfi_metadata_pass_through {
+ int enable;
+ u32 size;
+};
+
+struct hfi_multi_view_select {
+ u32 view_index;
+};
+
+struct hfi_hybrid_hierp {
+ u32 layers;
+};
+
+#define HFI_PRIORITY_LOW 10
+#define HFI_PRIOIRTY_MEDIUM 20
+#define HFI_PRIORITY_HIGH 30
+
+#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1)
+#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2)
+
+#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1)
+#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2)
+#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3)
+#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4)
+#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5)
+
+struct hfi_uncompressed_plane_actual_constraints_info {
+ u32 buffer_type;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+#define HFI_CMD_SYS_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000)
+#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001)
+#define HFI_CMD_SYS_PING (HFI_CMD_SYS_OX_START + 0x002)
+
+#define HFI_CMD_SESSION_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001)
+#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002)
+#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003)
+#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004)
+#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005)
+#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006)
+#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007)
+#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008)
+#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009)
+#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \
+ (HFI_CMD_SESSION_OX_START + 0x00A)
+#define HFI_CMD_SESSION_RELEASE_BUFFERS \
+ (HFI_CMD_SESSION_OX_START + 0x00B)
+#define HFI_CMD_SESSION_RELEASE_RESOURCES \
+ (HFI_CMD_SESSION_OX_START + 0x00C)
+
+#define HFI_MSG_SYS_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2)
+#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4)
+
+#define HFI_MSG_SESSION_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1)
+#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2)
+#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3)
+#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4)
+#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5)
+#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6)
+#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7)
+#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8)
+#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9)
+#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xA)
+#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xB)
+#define HFI_MSG_SESSION_RELEASE_BUFFERS_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xC)
+
+#define VIDC_IFACEQ_MAX_PKT_SIZE 1024
+#define VIDC_IFACEQ_MED_PKT_SIZE 768
+#define VIDC_IFACEQ_MIN_PKT_SIZE 8
+#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100
+#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512
+#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE (1024*12)
+
+
+struct hfi_cmd_sys_session_abort_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_ping_packet {
+ u32 size;
+ u32 packet_type;
+ u32 client_data;
+};
+
+struct hfi_cmd_session_load_resources_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_start_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_stop_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_empty_buffer_compressed_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 view_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 input_tag;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 packet_buffer2;
+ u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 packet_buffer3;
+ u32 rgData[1];
+};
+
+struct hfi_cmd_session_fill_buffer_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 output_tag;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[1];
+};
+
+struct hfi_cmd_session_flush_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 flush_type;
+};
+
+struct hfi_cmd_session_suspend_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_resume_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_get_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_session_release_buffer_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 extra_data_size;
+ int response_req;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_resources_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_parse_sequence_header_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 header_len;
+ u32 packet_buffer;
+};
+
+struct hfi_msg_sys_session_abort_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_idle_packet {
+ u32 size;
+ u32 packet_type;
+};
+
+struct hfi_msg_sys_ping_ack_packet {
+ u32 size;
+ u32 packet_type;
+ u32 client_data;
+};
+
+struct hfi_msg_sys_property_info_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_load_resources_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_start_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_stop_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_suspend_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_resume_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_flush_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 flush_type;
+};
+
+struct hfi_msg_session_empty_buffer_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 offset;
+ u32 filled_len;
+ u32 input_tag;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_compressed_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 error_type;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ u32 output_tag;
+ u32 picture_type;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fbd_uncompressed_plane0_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u32 view_id;
+ u32 error_type;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_x_coord;
+ u32 start_y_coord;
+ u32 input_tag;
+ u32 input_tag2;
+ u32 output_tag;
+ u32 picture_type;
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 packet_buffer2;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 packet_buffer3;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_parse_sequence_header_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_property_info_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_release_resources_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_release_buffers_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_extradata_mb_quantization_payload {
+ u8 rg_mb_qp[1];
+};
+
+struct hfi_extradata_vc1_pswnd {
+ u32 ps_wnd_h_offset;
+ u32 ps_wnd_v_offset;
+ u32 ps_wnd_width;
+ u32 ps_wnd_height;
+};
+
+struct hfi_extradata_vc1_framedisp_payload {
+ u32 res_pic;
+ u32 ref;
+ u32 range_map_present;
+ u32 range_map_y;
+ u32 range_map_uv;
+ u32 num_pan_scan_wnds;
+ struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
+};
+
+struct hfi_extradata_vc1_seqdisp_payload {
+ u32 prog_seg_frm;
+ u32 uv_sampling_fmt;
+ u32 color_fmt_flag;
+ u32 color_primaries;
+ u32 transfer_char;
+ u32 mat_coeff;
+ u32 aspect_ratio;
+ u32 aspect_horiz;
+ u32 aspect_vert;
+};
+
+struct hfi_extradata_timestamp_payload {
+ u32 time_stamp_low;
+ u32 time_stamp_high;
+};
+
+
+struct hfi_extradata_s3d_frame_packing_payload {
+ u32 fpa_id;
+ int cancel_flag;
+ u32 fpa_type;
+ int quin_cunx_flag;
+ u32 content_interprtation_type;
+ int spatial_flipping_flag;
+ int frame0_flipped_flag;
+ int field_views_flag;
+ int current_frame_isFrame0_flag;
+ int frame0_self_contained_flag;
+ int frame1_self_contained_flag;
+ u32 frame0_graid_pos_x;
+ u32 frame0_graid_pos_y;
+ u32 frame1_graid_pos_x;
+ u32 frame1_graid_pos_y;
+ u32 fpa_reserved_byte;
+ u32 fpa_repetition_period;
+ int fpa_extension_flag;
+};
+
+struct hfi_extradata_interlace_video_payload {
+ u32 format;
+};
+
+struct hfi_extradata_num_concealed_mb_payload {
+ u32 num_mb_concealed;
+};
+
+struct hfi_extradata_sliceinfo {
+ u32 offset_in_stream;
+ u32 slice_length;
+};
+
+struct hfi_extradata_multislice_info_payload {
+ u32 num_slices;
+ struct hfi_extradata_sliceinfo rg_slice_info[1];
+};
+
+struct hfi_index_extradata_input_crop_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_index_extradata_digital_zoom_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ int width;
+ int height;
+};
+
+struct hfi_index_extradata_aspect_ratio_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 aspect_width;
+ u32 aspect_height;
+};
+struct hfi_extradata_panscan_wndw_payload {
+ u32 num_window;
+ struct hfi_extradata_vc1_pswnd wnd[1];
+};
+
+struct hfi_extradata_frame_type_payload {
+ u32 frame_rate;
+};
+
+struct hfi_extradata_recovery_point_sei_payload {
+ u32 flag;
+};
+
+struct hal_session {
+ struct list_head list;
+ void *session_id;
+ bool is_decoder;
+ void *device;
+};
+
+struct hal_device_data {
+ struct list_head dev_head;
+ int dev_count;
+};
+
+struct msm_vidc_fw {
+ void *cookie;
+};
+
+u32 hfi_process_msg_packet(msm_vidc_callback callback,
+ u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+ struct list_head *sessions, struct mutex *session_lock);
+
+struct hal_session *hfi_process_get_session(
+ struct list_head *sessions, u32 session_id);
+#endif
+
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
new file mode 100644
index 000000000000..5bf0d98d74dd
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -0,0 +1,1392 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+
+#ifndef __VIDC_HFI_API_H__
+#define __VIDC_HFI_API_H__
+
+#include <linux/log2.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_resources.h"
+
+#define CONTAINS(__a, __sz, __t) ({\
+ int __rc = __t >= __a && \
+ __t < __a + __sz; \
+ __rc; \
+})
+
+#define OVERLAPS(__t, __tsz, __a, __asz) ({\
+ int __rc = __t <= __a && \
+ __t + __tsz >= __a + __asz; \
+ __rc; \
+})
+
+#define HAL_BUFFERFLAG_EOS 0x00000001
+#define HAL_BUFFERFLAG_STARTTIME 0x00000002
+#define HAL_BUFFERFLAG_DECODEONLY 0x00000004
+#define HAL_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HAL_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HAL_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HAL_BUFFERFLAG_EXTRADATA 0x00000040
+#define HAL_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HAL_BUFFERFLAG_READONLY 0x00000200
+#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HAL_BUFFERFLAG_EOSEQ 0x00200000
+#define HAL_BUFFERFLAG_MBAFF 0x08000000
+#define HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP 0x10000000
+#define HAL_BUFFERFLAG_DROP_FRAME 0x20000000
+#define HAL_BUFFERFLAG_TS_DISCONTINUITY 0x40000000
+#define HAL_BUFFERFLAG_TS_ERROR 0x80000000
+
+
+
+#define HAL_DEBUG_MSG_LOW 0x00000001
+#define HAL_DEBUG_MSG_MEDIUM 0x00000002
+#define HAL_DEBUG_MSG_HIGH 0x00000004
+#define HAL_DEBUG_MSG_ERROR 0x00000008
+#define HAL_DEBUG_MSG_FATAL 0x00000010
+#define MAX_PROFILE_COUNT 16
+
+#define HAL_MAX_MATRIX_COEFFS 9
+#define HAL_MAX_BIAS_COEFFS 3
+#define HAL_MAX_LIMIT_COEFFS 6
+
+enum vidc_status {
+ VIDC_ERR_NONE = 0x0,
+ VIDC_ERR_FAIL = 0x80000000,
+ VIDC_ERR_ALLOC_FAIL,
+ VIDC_ERR_ILLEGAL_OP,
+ VIDC_ERR_BAD_PARAM,
+ VIDC_ERR_BAD_HANDLE,
+ VIDC_ERR_NOT_SUPPORTED,
+ VIDC_ERR_BAD_STATE,
+ VIDC_ERR_MAX_CLIENTS,
+ VIDC_ERR_IFRAME_EXPECTED,
+ VIDC_ERR_HW_FATAL,
+ VIDC_ERR_BITSTREAM_ERR,
+ VIDC_ERR_INDEX_NOMORE,
+ VIDC_ERR_SEQHDR_PARSE_FAIL,
+ VIDC_ERR_INSUFFICIENT_BUFFER,
+ VIDC_ERR_BAD_POWER_STATE,
+ VIDC_ERR_NO_VALID_SESSION,
+ VIDC_ERR_TIMEOUT,
+ VIDC_ERR_CMDQFULL,
+ VIDC_ERR_START_CODE_NOT_FOUND,
+ VIDC_ERR_CLIENT_PRESENT = 0x90000001,
+ VIDC_ERR_CLIENT_FATAL,
+ VIDC_ERR_CMD_QUEUE_FULL,
+ VIDC_ERR_UNUSED = 0x10000000
+};
+
+enum hal_extradata_id {
+ HAL_EXTRADATA_NONE,
+ HAL_EXTRADATA_MB_QUANTIZATION,
+ HAL_EXTRADATA_INTERLACE_VIDEO,
+ HAL_EXTRADATA_VC1_FRAMEDISP,
+ HAL_EXTRADATA_VC1_SEQDISP,
+ HAL_EXTRADATA_TIMESTAMP,
+ HAL_EXTRADATA_S3D_FRAME_PACKING,
+ HAL_EXTRADATA_FRAME_RATE,
+ HAL_EXTRADATA_PANSCAN_WINDOW,
+ HAL_EXTRADATA_RECOVERY_POINT_SEI,
+ HAL_EXTRADATA_MULTISLICE_INFO,
+ HAL_EXTRADATA_INDEX,
+ HAL_EXTRADATA_NUM_CONCEALED_MB,
+ HAL_EXTRADATA_METADATA_FILLER,
+ HAL_EXTRADATA_ASPECT_RATIO,
+ HAL_EXTRADATA_MPEG2_SEQDISP,
+ HAL_EXTRADATA_STREAM_USERDATA,
+ HAL_EXTRADATA_FRAME_QP,
+ HAL_EXTRADATA_FRAME_BITS_INFO,
+ HAL_EXTRADATA_INPUT_CROP,
+ HAL_EXTRADATA_DIGITAL_ZOOM,
+ HAL_EXTRADATA_LTR_INFO,
+ HAL_EXTRADATA_METADATA_MBI,
+};
+
+enum hal_property {
+ HAL_CONFIG_FRAME_RATE = 0x04000001,
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
+ HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+ HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
+ HAL_PARAM_INDEX_EXTRADATA,
+ HAL_PARAM_FRAME_SIZE,
+ HAL_CONFIG_REALTIME,
+ HAL_PARAM_BUFFER_COUNT_ACTUAL,
+ HAL_PARAM_BUFFER_SIZE_ACTUAL,
+ HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL,
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+ HAL_PARAM_VDEC_OUTPUT_ORDER,
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+ HAL_PARAM_VDEC_MULTI_STREAM,
+ HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
+ HAL_PARAM_DIVX_FORMAT,
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+ HAL_CONFIG_VDEC_MB_ERROR_MAP,
+ HAL_CONFIG_VENC_REQUEST_IFRAME,
+ HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
+ HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
+ HAL_CONFIG_VENC_TARGET_BITRATE,
+ HAL_PARAM_PROFILE_LEVEL_CURRENT,
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+ HAL_PARAM_VENC_RATE_CONTROL,
+ HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
+ HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
+ HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
+ HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
+ HAL_PARAM_VENC_SESSION_QP,
+ HAL_PARAM_VENC_SESSION_QP_RANGE,
+ HAL_CONFIG_VENC_INTRA_PERIOD,
+ HAL_CONFIG_VENC_IDR_PERIOD,
+ HAL_CONFIG_VPE_OPERATIONS,
+ HAL_PARAM_VENC_INTRA_REFRESH,
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
+ HAL_CONFIG_VPE_DEINTERLACE,
+ HAL_SYS_DEBUG_CONFIG,
+ HAL_CONFIG_BUFFER_REQUIREMENTS,
+ HAL_CONFIG_PRIORITY,
+ HAL_CONFIG_BATCH_INFO,
+ HAL_PARAM_METADATA_PASS_THROUGH,
+ HAL_SYS_IDLE_INDICATOR,
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
+ HAL_PARAM_INTERLACE_FORMAT_SUPPORTED,
+ HAL_PARAM_CHROMA_SITE,
+ HAL_PARAM_PROPERTIES_SUPPORTED,
+ HAL_PARAM_PROFILE_LEVEL_SUPPORTED,
+ HAL_PARAM_CAPABILITY_SUPPORTED,
+ HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
+ HAL_PARAM_MULTI_VIEW_FORMAT,
+ HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE,
+ HAL_PARAM_CODEC_SUPPORTED,
+ HAL_PARAM_VDEC_MULTI_VIEW_SELECT,
+ HAL_PARAM_VDEC_MB_QUANTIZATION,
+ HAL_PARAM_VDEC_NUM_CONCEALED_MB,
+ HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
+ HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
+ HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
+ HAL_CONFIG_BUFFER_COUNT_ACTUAL,
+ HAL_CONFIG_VDEC_MULTI_STREAM,
+ HAL_PARAM_VENC_MULTI_SLICE_INFO,
+ HAL_CONFIG_VENC_TIMESTAMP_SCALE,
+ HAL_PARAM_VENC_LOW_LATENCY,
+ HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+ HAL_PARAM_VDEC_SYNC_FRAME_DECODE,
+ HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+ HAL_CONFIG_VENC_MAX_BITRATE,
+ HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
+ HAL_PARAM_VENC_H264_GENERATE_AUDNAL,
+ HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
+ HAL_PARAM_BUFFER_ALLOC_MODE,
+ HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+ HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
+ HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY,
+ HAL_PARAM_VDEC_CONCEAL_COLOR,
+ HAL_PARAM_VDEC_SCS_THRESHOLD,
+ HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+ HAL_PARAM_MVC_BUFFER_LAYOUT,
+ HAL_PARAM_VENC_LTRMODE,
+ HAL_CONFIG_VENC_MARKLTRFRAME,
+ HAL_CONFIG_VENC_USELTRFRAME,
+ HAL_CONFIG_VENC_LTRPERIOD,
+ HAL_CONFIG_VENC_HIER_P_NUM_FRAMES,
+ HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS,
+ HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP,
+ HAL_PARAM_VENC_ENABLE_INITIAL_QP,
+ HAL_PARAM_VENC_SEARCH_RANGE,
+ HAL_PARAM_VPE_COLOR_SPACE_CONVERSION,
+ HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
+ HAL_PARAM_VENC_H264_NAL_SVC_EXT,
+ HAL_CONFIG_VENC_PERF_MODE,
+ HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS,
+ HAL_PARAM_VDEC_NON_SECURE_OUTPUT2,
+ HAL_PARAM_VENC_HIER_P_HYBRID_MODE,
+};
+
+enum hal_domain {
+ HAL_VIDEO_DOMAIN_VPE,
+ HAL_VIDEO_DOMAIN_ENCODER,
+ HAL_VIDEO_DOMAIN_DECODER,
+ HAL_UNUSED_DOMAIN = 0x10000000,
+};
+
+enum multi_stream {
+ HAL_VIDEO_DECODER_NONE = 0x00000000,
+ HAL_VIDEO_DECODER_PRIMARY = 0x00000001,
+ HAL_VIDEO_DECODER_SECONDARY = 0x00000002,
+ HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004,
+ HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000,
+};
+
+enum hal_core_capabilities {
+ HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001,
+ HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002,
+ HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004,
+ HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008,
+ HAL_VIDEO_UNUSED_CAPABILITY = 0x10000000,
+};
+
+enum hal_default_properties {
+ HAL_VIDEO_DYNAMIC_BUF_MODE = 0x00000001,
+ HAL_VIDEO_CONTINUE_DATA_TRANSFER = 0x00000002,
+};
+
+enum hal_video_codec {
+ HAL_VIDEO_CODEC_UNKNOWN = 0x00000000,
+ HAL_VIDEO_CODEC_MVC = 0x00000001,
+ HAL_VIDEO_CODEC_H264 = 0x00000002,
+ HAL_VIDEO_CODEC_H263 = 0x00000004,
+ HAL_VIDEO_CODEC_MPEG1 = 0x00000008,
+ HAL_VIDEO_CODEC_MPEG2 = 0x00000010,
+ HAL_VIDEO_CODEC_MPEG4 = 0x00000020,
+ HAL_VIDEO_CODEC_DIVX_311 = 0x00000040,
+ HAL_VIDEO_CODEC_DIVX = 0x00000080,
+ HAL_VIDEO_CODEC_VC1 = 0x00000100,
+ HAL_VIDEO_CODEC_SPARK = 0x00000200,
+ HAL_VIDEO_CODEC_VP6 = 0x00000400,
+ HAL_VIDEO_CODEC_VP7 = 0x00000800,
+ HAL_VIDEO_CODEC_VP8 = 0x00001000,
+ HAL_VIDEO_CODEC_HEVC = 0x00002000,
+ HAL_VIDEO_CODEC_HEVC_HYBRID = 0x00004000,
+ HAL_UNUSED_CODEC = 0x10000000,
+};
+
+enum hal_h263_profile {
+ HAL_H263_PROFILE_BASELINE = 0x00000001,
+ HAL_H263_PROFILE_H320CODING = 0x00000002,
+ HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
+ HAL_H263_PROFILE_ISWV2 = 0x00000008,
+ HAL_H263_PROFILE_ISWV3 = 0x00000010,
+ HAL_H263_PROFILE_HIGHCOMPRESSION = 0x00000020,
+ HAL_H263_PROFILE_INTERNET = 0x00000040,
+ HAL_H263_PROFILE_INTERLACE = 0x00000080,
+ HAL_H263_PROFILE_HIGHLATENCY = 0x00000100,
+ HAL_UNUSED_H263_PROFILE = 0x10000000,
+};
+
+enum hal_h263_level {
+ HAL_H263_LEVEL_10 = 0x00000001,
+ HAL_H263_LEVEL_20 = 0x00000002,
+ HAL_H263_LEVEL_30 = 0x00000004,
+ HAL_H263_LEVEL_40 = 0x00000008,
+ HAL_H263_LEVEL_45 = 0x00000010,
+ HAL_H263_LEVEL_50 = 0x00000020,
+ HAL_H263_LEVEL_60 = 0x00000040,
+ HAL_H263_LEVEL_70 = 0x00000080,
+ HAL_UNUSED_H263_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg2_profile {
+ HAL_MPEG2_PROFILE_SIMPLE = 0x00000001,
+ HAL_MPEG2_PROFILE_MAIN = 0x00000002,
+ HAL_MPEG2_PROFILE_422 = 0x00000004,
+ HAL_MPEG2_PROFILE_SNR = 0x00000008,
+ HAL_MPEG2_PROFILE_SPATIAL = 0x00000010,
+ HAL_MPEG2_PROFILE_HIGH = 0x00000020,
+ HAL_UNUSED_MPEG2_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg2_level {
+ HAL_MPEG2_LEVEL_LL = 0x00000001,
+ HAL_MPEG2_LEVEL_ML = 0x00000002,
+ HAL_MPEG2_LEVEL_H14 = 0x00000004,
+ HAL_MPEG2_LEVEL_HL = 0x00000008,
+ HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg4_profile {
+ HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
+ HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002,
+ HAL_MPEG4_PROFILE_CORE = 0x00000004,
+ HAL_MPEG4_PROFILE_MAIN = 0x00000008,
+ HAL_MPEG4_PROFILE_NBIT = 0x00000010,
+ HAL_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020,
+ HAL_MPEG4_PROFILE_SIMPLEFACE = 0x00000040,
+ HAL_MPEG4_PROFILE_SIMPLEFBA = 0x00000080,
+ HAL_MPEG4_PROFILE_BASICANIMATED = 0x00000100,
+ HAL_MPEG4_PROFILE_HYBRID = 0x00000200,
+ HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
+ HAL_MPEG4_PROFILE_CORESCALABLE = 0x00000800,
+ HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
+ HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
+ HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
+ HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000,
+ HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg4_level {
+ HAL_MPEG4_LEVEL_0 = 0x00000001,
+ HAL_MPEG4_LEVEL_0b = 0x00000002,
+ HAL_MPEG4_LEVEL_1 = 0x00000004,
+ HAL_MPEG4_LEVEL_2 = 0x00000008,
+ HAL_MPEG4_LEVEL_3 = 0x00000010,
+ HAL_MPEG4_LEVEL_4 = 0x00000020,
+ HAL_MPEG4_LEVEL_4a = 0x00000040,
+ HAL_MPEG4_LEVEL_5 = 0x00000080,
+ HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
+ HAL_MPEG4_LEVEL_6 = 0x7F000001,
+ HAL_MPEG4_LEVEL_7 = 0x7F000002,
+ HAL_MPEG4_LEVEL_8 = 0x7F000003,
+ HAL_MPEG4_LEVEL_9 = 0x7F000004,
+ HAL_MPEG4_LEVEL_3b = 0x7F000005,
+ HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
+};
+
+enum hal_h264_profile {
+ HAL_H264_PROFILE_BASELINE = 0x00000001,
+ HAL_H264_PROFILE_MAIN = 0x00000002,
+ HAL_H264_PROFILE_HIGH = 0x00000004,
+ HAL_H264_PROFILE_EXTENDED = 0x00000008,
+ HAL_H264_PROFILE_HIGH10 = 0x00000010,
+ HAL_H264_PROFILE_HIGH422 = 0x00000020,
+ HAL_H264_PROFILE_HIGH444 = 0x00000040,
+ HAL_H264_PROFILE_CONSTRAINED_BASE = 0x00000080,
+ HAL_H264_PROFILE_CONSTRAINED_HIGH = 0x00000100,
+ HAL_UNUSED_H264_PROFILE = 0x10000000,
+};
+
+enum hal_h264_level {
+ HAL_H264_LEVEL_1 = 0x00000001,
+ HAL_H264_LEVEL_1b = 0x00000002,
+ HAL_H264_LEVEL_11 = 0x00000004,
+ HAL_H264_LEVEL_12 = 0x00000008,
+ HAL_H264_LEVEL_13 = 0x00000010,
+ HAL_H264_LEVEL_2 = 0x00000020,
+ HAL_H264_LEVEL_21 = 0x00000040,
+ HAL_H264_LEVEL_22 = 0x00000080,
+ HAL_H264_LEVEL_3 = 0x00000100,
+ HAL_H264_LEVEL_31 = 0x00000200,
+ HAL_H264_LEVEL_32 = 0x00000400,
+ HAL_H264_LEVEL_4 = 0x00000800,
+ HAL_H264_LEVEL_41 = 0x00001000,
+ HAL_H264_LEVEL_42 = 0x00002000,
+ HAL_H264_LEVEL_5 = 0x00004000,
+ HAL_H264_LEVEL_51 = 0x00008000,
+ HAL_H264_LEVEL_52 = 0x00010000,
+ HAL_UNUSED_H264_LEVEL = 0x10000000,
+};
+
+enum hal_hevc_profile {
+ HAL_HEVC_PROFILE_MAIN = 0x00000001,
+ HAL_HEVC_PROFILE_MAIN10 = 0x00000002,
+ HAL_HEVC_PROFILE_MAIN_STILL_PIC = 0x00000004,
+ HAL_UNUSED_HEVC_PROFILE = 0x10000000,
+};
+
+enum hal_hevc_level {
+ HAL_HEVC_MAIN_TIER_LEVEL_1 = 0x10000001,
+ HAL_HEVC_MAIN_TIER_LEVEL_2 = 0x10000002,
+ HAL_HEVC_MAIN_TIER_LEVEL_2_1 = 0x10000004,
+ HAL_HEVC_MAIN_TIER_LEVEL_3 = 0x10000008,
+ HAL_HEVC_MAIN_TIER_LEVEL_3_1 = 0x10000010,
+ HAL_HEVC_MAIN_TIER_LEVEL_4 = 0x10000020,
+ HAL_HEVC_MAIN_TIER_LEVEL_4_1 = 0x10000040,
+ HAL_HEVC_MAIN_TIER_LEVEL_5 = 0x10000080,
+ HAL_HEVC_MAIN_TIER_LEVEL_5_1 = 0x10000100,
+ HAL_HEVC_MAIN_TIER_LEVEL_5_2 = 0x10000200,
+ HAL_HEVC_MAIN_TIER_LEVEL_6 = 0x10000400,
+ HAL_HEVC_MAIN_TIER_LEVEL_6_1 = 0x10000800,
+ HAL_HEVC_MAIN_TIER_LEVEL_6_2 = 0x10001000,
+ HAL_HEVC_HIGH_TIER_LEVEL_1 = 0x20000001,
+ HAL_HEVC_HIGH_TIER_LEVEL_2 = 0x20000002,
+ HAL_HEVC_HIGH_TIER_LEVEL_2_1 = 0x20000004,
+ HAL_HEVC_HIGH_TIER_LEVEL_3 = 0x20000008,
+ HAL_HEVC_HIGH_TIER_LEVEL_3_1 = 0x20000010,
+ HAL_HEVC_HIGH_TIER_LEVEL_4 = 0x20000020,
+ HAL_HEVC_HIGH_TIER_LEVEL_4_1 = 0x20000040,
+ HAL_HEVC_HIGH_TIER_LEVEL_5 = 0x20000080,
+ HAL_HEVC_HIGH_TIER_LEVEL_5_1 = 0x20000100,
+ HAL_HEVC_HIGH_TIER_LEVEL_5_2 = 0x20000200,
+ HAL_HEVC_HIGH_TIER_LEVEL_6 = 0x20000400,
+ HAL_HEVC_HIGH_TIER_LEVEL_6_1 = 0x20000800,
+ HAL_HEVC_HIGH_TIER_LEVEL_6_2 = 0x20001000,
+ HAL_UNUSED_HEVC_TIER_LEVEL = 0x80000000,
+};
+
+enum hal_hevc_tier {
+ HAL_HEVC_TIER_MAIN = 0x00000001,
+ HAL_HEVC_TIER_HIGH = 0x00000002,
+ HAL_UNUSED_HEVC_TIER = 0x10000000,
+};
+
+enum hal_vpx_profile {
+ HAL_VPX_PROFILE_SIMPLE = 0x00000001,
+ HAL_VPX_PROFILE_ADVANCED = 0x00000002,
+ HAL_VPX_PROFILE_VERSION_0 = 0x00000004,
+ HAL_VPX_PROFILE_VERSION_1 = 0x00000008,
+ HAL_VPX_PROFILE_VERSION_2 = 0x00000010,
+ HAL_VPX_PROFILE_VERSION_3 = 0x00000020,
+ HAL_VPX_PROFILE_UNUSED = 0x10000000,
+};
+
+enum hal_vc1_profile {
+ HAL_VC1_PROFILE_SIMPLE = 0x00000001,
+ HAL_VC1_PROFILE_MAIN = 0x00000002,
+ HAL_VC1_PROFILE_ADVANCED = 0x00000004,
+ HAL_UNUSED_VC1_PROFILE = 0x10000000,
+};
+
+enum hal_vc1_level {
+ HAL_VC1_LEVEL_LOW = 0x00000001,
+ HAL_VC1_LEVEL_MEDIUM = 0x00000002,
+ HAL_VC1_LEVEL_HIGH = 0x00000004,
+ HAL_VC1_LEVEL_0 = 0x00000008,
+ HAL_VC1_LEVEL_1 = 0x00000010,
+ HAL_VC1_LEVEL_2 = 0x00000020,
+ HAL_VC1_LEVEL_3 = 0x00000040,
+ HAL_VC1_LEVEL_4 = 0x00000080,
+ HAL_UNUSED_VC1_LEVEL = 0x10000000,
+};
+
+enum hal_divx_format {
+ HAL_DIVX_FORMAT_4,
+ HAL_DIVX_FORMAT_5,
+ HAL_DIVX_FORMAT_6,
+ HAL_UNUSED_DIVX_FORMAT = 0x10000000,
+};
+
+enum hal_divx_profile {
+ HAL_DIVX_PROFILE_QMOBILE = 0x00000001,
+ HAL_DIVX_PROFILE_MOBILE = 0x00000002,
+ HAL_DIVX_PROFILE_MT = 0x00000004,
+ HAL_DIVX_PROFILE_HT = 0x00000008,
+ HAL_DIVX_PROFILE_HD = 0x00000010,
+ HAL_UNUSED_DIVX_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_profile {
+ HAL_MVC_PROFILE_STEREO_HIGH = 0x00001000,
+ HAL_UNUSED_MVC_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_level {
+ HAL_MVC_LEVEL_1 = 0x00000001,
+ HAL_MVC_LEVEL_1b = 0x00000002,
+ HAL_MVC_LEVEL_11 = 0x00000004,
+ HAL_MVC_LEVEL_12 = 0x00000008,
+ HAL_MVC_LEVEL_13 = 0x00000010,
+ HAL_MVC_LEVEL_2 = 0x00000020,
+ HAL_MVC_LEVEL_21 = 0x00000040,
+ HAL_MVC_LEVEL_22 = 0x00000080,
+ HAL_MVC_LEVEL_3 = 0x00000100,
+ HAL_MVC_LEVEL_31 = 0x00000200,
+ HAL_MVC_LEVEL_32 = 0x00000400,
+ HAL_MVC_LEVEL_4 = 0x00000800,
+ HAL_MVC_LEVEL_41 = 0x00001000,
+ HAL_MVC_LEVEL_42 = 0x00002000,
+ HAL_MVC_LEVEL_5 = 0x00004000,
+ HAL_MVC_LEVEL_51 = 0x00008000,
+ HAL_UNUSED_MVC_LEVEL = 0x10000000,
+};
+
+struct hal_frame_rate {
+ enum hal_buffer buffer_type;
+ u32 frame_rate;
+};
+
+enum hal_uncompressed_format {
+ HAL_COLOR_FORMAT_MONOCHROME = 0x00000001,
+ HAL_COLOR_FORMAT_NV12 = 0x00000002,
+ HAL_COLOR_FORMAT_NV21 = 0x00000004,
+ HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008,
+ HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010,
+ HAL_COLOR_FORMAT_YUYV = 0x00000020,
+ HAL_COLOR_FORMAT_YVYU = 0x00000040,
+ HAL_COLOR_FORMAT_UYVY = 0x00000080,
+ HAL_COLOR_FORMAT_VYUY = 0x00000100,
+ HAL_COLOR_FORMAT_RGB565 = 0x00000200,
+ HAL_COLOR_FORMAT_BGR565 = 0x00000400,
+ HAL_COLOR_FORMAT_RGB888 = 0x00000800,
+ HAL_COLOR_FORMAT_BGR888 = 0x00001000,
+ HAL_COLOR_FORMAT_NV12_UBWC = 0x00002000,
+ HAL_COLOR_FORMAT_NV12_TP10_UBWC = 0x00004000,
+ HAL_UNUSED_COLOR = 0x10000000,
+};
+
+enum hal_ssr_trigger_type {
+ SSR_ERR_FATAL = 1,
+ SSR_SW_DIV_BY_ZERO,
+ SSR_HW_WDOG_IRQ,
+};
+
+struct hal_uncompressed_format_select {
+ enum hal_buffer buffer_type;
+ enum hal_uncompressed_format format;
+};
+
+struct hal_uncompressed_plane_actual {
+ int actual_stride;
+ u32 actual_plane_buffer_height;
+};
+
+struct hal_uncompressed_plane_actual_info {
+ enum hal_buffer buffer_type;
+ u32 num_planes;
+ struct hal_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hal_uncompressed_plane_constraints {
+ u32 stride_multiples;
+ u32 max_stride;
+ u32 min_plane_buffer_height_multiple;
+ u32 buffer_alignment;
+};
+
+struct hal_uncompressed_plane_actual_constraints_info {
+ enum hal_buffer buffer_type;
+ u32 num_planes;
+ struct hal_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hal_extra_data_header_config {
+ u32 type;
+ enum hal_buffer buffer_type;
+ u32 version;
+ u32 port_index;
+ u32 client_extradata_id;
+};
+
+struct hal_frame_size {
+ enum hal_buffer buffer_type;
+ u32 width;
+ u32 height;
+};
+
+struct hal_enable {
+ u32 enable;
+};
+
+struct hal_buffer_count_actual {
+ enum hal_buffer buffer_type;
+ u32 buffer_count_actual;
+};
+
+struct hal_buffer_size_actual {
+ enum hal_buffer buffer_type;
+ u32 buffer_size;
+};
+
+struct hal_buffer_display_hold_count_actual {
+ enum hal_buffer buffer_type;
+ u32 hold_count;
+};
+
+enum hal_nal_stream_format {
+ HAL_NAL_FORMAT_STARTCODES = 0x00000001,
+ HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
+ HAL_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004,
+ HAL_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008,
+ HAL_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010,
+};
+
+enum hal_output_order {
+ HAL_OUTPUT_ORDER_DISPLAY,
+ HAL_OUTPUT_ORDER_DECODE,
+ HAL_UNUSED_OUTPUT = 0x10000000,
+};
+
+enum hal_picture {
+ HAL_PICTURE_I = 0x01,
+ HAL_PICTURE_P = 0x02,
+ HAL_PICTURE_B = 0x04,
+ HAL_PICTURE_IDR = 0x08,
+ HAL_FRAME_NOTCODED = 0x7F002000,
+ HAL_FRAME_YUV = 0x7F004000,
+ HAL_UNUSED_PICT = 0x10000000,
+};
+
+struct hal_extradata_enable {
+ u32 enable;
+ enum hal_extradata_id index;
+};
+
+struct hal_enable_picture {
+ u32 picture_type;
+};
+
+struct hal_multi_stream {
+ enum hal_buffer buffer_type;
+ u32 enable;
+ u32 width;
+ u32 height;
+};
+
+struct hal_display_picture_buffer_count {
+ u32 enable;
+ u32 count;
+};
+
+struct hal_mb_error_map {
+ u32 error_map_size;
+ u8 rg_error_map[1];
+};
+
+struct hal_request_iframe {
+ u32 enable;
+};
+
+struct hal_bitrate {
+ u32 bit_rate;
+ u32 layer_id;
+};
+
+struct hal_profile_level {
+ u32 profile;
+ u32 level;
+};
+
+struct hal_profile_level_supported {
+ u32 profile_count;
+ struct hal_profile_level profile_level[MAX_PROFILE_COUNT];
+};
+
+enum hal_h264_entropy {
+ HAL_H264_ENTROPY_CAVLC = 1,
+ HAL_H264_ENTROPY_CABAC = 2,
+ HAL_UNUSED_ENTROPY = 0x10000000,
+};
+
+enum hal_h264_cabac_model {
+ HAL_H264_CABAC_MODEL_0 = 1,
+ HAL_H264_CABAC_MODEL_1 = 2,
+ HAL_H264_CABAC_MODEL_2 = 4,
+ HAL_UNUSED_CABAC = 0x10000000,
+};
+
+struct hal_h264_entropy_control {
+ enum hal_h264_entropy entropy_mode;
+ enum hal_h264_cabac_model cabac_model;
+};
+
+enum hal_rate_control {
+ HAL_RATE_CONTROL_OFF,
+ HAL_RATE_CONTROL_VBR_VFR,
+ HAL_RATE_CONTROL_VBR_CFR,
+ HAL_RATE_CONTROL_CBR_VFR,
+ HAL_RATE_CONTROL_CBR_CFR,
+ HAL_UNUSED_RC = 0x10000000,
+};
+
+struct hal_mpeg4_time_resolution {
+ u32 time_increment_resolution;
+};
+
+struct hal_mpeg4_header_extension {
+ u32 header_extension;
+};
+
+enum hal_h264_db_mode {
+ HAL_H264_DB_MODE_DISABLE,
+ HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
+ HAL_H264_DB_MODE_ALL_BOUNDARY,
+ HAL_UNUSED_H264_DB = 0x10000000,
+};
+
+struct hal_h264_db_control {
+ enum hal_h264_db_mode mode;
+ int slice_alpha_offset;
+ int slice_beta_offset;
+};
+
+struct hal_temporal_spatial_tradeoff {
+ u32 ts_factor;
+};
+
+struct hal_quantization {
+ u32 qpi;
+ u32 qpp;
+ u32 qpb;
+ u32 layer_id;
+};
+
+struct hal_initial_quantization {
+ u32 qpi;
+ u32 qpp;
+ u32 qpb;
+ u32 init_qp_enable;
+};
+
+struct hal_quantization_range {
+ u32 min_qp;
+ u32 max_qp;
+ u32 layer_id;
+};
+
+struct hal_intra_period {
+ u32 pframes;
+ u32 bframes;
+};
+
+struct hal_idr_period {
+ u32 idr_period;
+};
+
+enum hal_rotate {
+ HAL_ROTATE_NONE,
+ HAL_ROTATE_90,
+ HAL_ROTATE_180,
+ HAL_ROTATE_270,
+ HAL_UNUSED_ROTATE = 0x10000000,
+};
+
+enum hal_flip {
+ HAL_FLIP_NONE,
+ HAL_FLIP_HORIZONTAL,
+ HAL_FLIP_VERTICAL,
+ HAL_UNUSED_FLIP = 0x10000000,
+};
+
+struct hal_operations {
+ enum hal_rotate rotate;
+ enum hal_flip flip;
+};
+
+enum hal_intra_refresh_mode {
+ HAL_INTRA_REFRESH_NONE,
+ HAL_INTRA_REFRESH_CYCLIC,
+ HAL_INTRA_REFRESH_ADAPTIVE,
+ HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE,
+ HAL_INTRA_REFRESH_RANDOM,
+ HAL_UNUSED_INTRA = 0x10000000,
+};
+
+struct hal_intra_refresh {
+ enum hal_intra_refresh_mode mode;
+ u32 air_mbs;
+ u32 air_ref;
+ u32 cir_mbs;
+};
+
+enum hal_multi_slice {
+ HAL_MULTI_SLICE_OFF,
+ HAL_MULTI_SLICE_BY_MB_COUNT,
+ HAL_MULTI_SLICE_BY_BYTE_COUNT,
+ HAL_MULTI_SLICE_GOB,
+ HAL_UNUSED_SLICE = 0x10000000,
+};
+
+struct hal_multi_slice_control {
+ enum hal_multi_slice multi_slice;
+ u32 slice_size;
+};
+
+struct hal_debug_config {
+ u32 debug_config;
+};
+
+struct hal_buffer_requirements {
+ enum hal_buffer buffer_type;
+ u32 buffer_size;
+ u32 buffer_region_size;
+ u32 buffer_hold_count;
+ u32 buffer_count_min;
+ u32 buffer_count_actual;
+ u32 contiguous;
+ u32 buffer_alignment;
+};
+
+enum hal_priority {/* Priority increases with number */
+ HAL_PRIORITY_LOW = 10,
+ HAL_PRIOIRTY_MEDIUM = 20,
+ HAL_PRIORITY_HIGH = 30,
+ HAL_UNUSED_PRIORITY = 0x10000000,
+};
+
+struct hal_batch_info {
+ u32 input_batch_count;
+ u32 output_batch_count;
+};
+
+struct hal_metadata_pass_through {
+ u32 enable;
+ u32 size;
+};
+
+struct hal_uncompressed_format_supported {
+ enum hal_buffer buffer_type;
+ u32 format_entries;
+ u32 rg_format_info[1];
+};
+
+enum hal_interlace_format {
+ HAL_INTERLACE_FRAME_PROGRESSIVE = 0x01,
+ HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
+ HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+ HAL_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
+ HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+ HAL_UNUSED_INTERLACE = 0x10000000,
+};
+
+struct hal_interlace_format_supported {
+ enum hal_buffer buffer_type;
+ enum hal_interlace_format format;
+};
+
+enum hal_chroma_site {
+ HAL_CHROMA_SITE_0,
+ HAL_CHROMA_SITE_1,
+ HAL_UNUSED_CHROMA = 0x10000000,
+};
+
+struct hal_properties_supported {
+ u32 num_properties;
+ u32 rg_properties[1];
+};
+
+enum hal_capability {
+ HAL_CAPABILITY_FRAME_WIDTH,
+ HAL_CAPABILITY_FRAME_HEIGHT,
+ HAL_CAPABILITY_MBS_PER_FRAME,
+ HAL_CAPABILITY_MBS_PER_SECOND,
+ HAL_CAPABILITY_FRAMERATE,
+ HAL_CAPABILITY_SCALE_X,
+ HAL_CAPABILITY_SCALE_Y,
+ HAL_CAPABILITY_BITRATE,
+ HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD,
+ HAL_UNUSED_CAPABILITY = 0x10000000,
+};
+
+struct hal_capability_supported {
+ enum hal_capability capability_type;
+ u32 min;
+ u32 max;
+ u32 step_size;
+};
+
+struct hal_capability_supported_info {
+ u32 num_capabilities;
+ struct hal_capability_supported rg_data[1];
+};
+
+struct hal_nal_stream_format_supported {
+ u32 nal_stream_format_supported;
+};
+
+struct hal_nal_stream_format_select {
+ u32 nal_stream_format_select;
+};
+
+struct hal_multi_view_format {
+ u32 views;
+ u32 rg_view_order[1];
+};
+
+enum hal_buffer_layout_type {
+ HAL_BUFFER_LAYOUT_TOP_BOTTOM,
+ HAL_BUFFER_LAYOUT_SEQ,
+ HAL_UNUSED_BUFFER_LAYOUT = 0x10000000,
+};
+
+struct hal_mvc_buffer_layout {
+ enum hal_buffer_layout_type layout_type;
+ u32 bright_view_first;
+ u32 ngap;
+};
+
+struct hal_seq_header_info {
+ u32 nax_header_len;
+};
+
+struct hal_codec_supported {
+ u32 decoder_codec_supported;
+ u32 encoder_codec_supported;
+};
+
+struct hal_multi_view_select {
+ u32 view_index;
+};
+
+struct hal_timestamp_scale {
+ u32 time_stamp_scale;
+};
+
+
+struct hal_h264_vui_timing_info {
+ u32 enable;
+ u32 fixed_frame_rate;
+ u32 time_scale;
+};
+
+struct hal_h264_vui_bitstream_restrc {
+ u32 enable;
+};
+
+struct hal_preserve_text_quality {
+ u32 enable;
+};
+
+struct hal_vc1e_perf_cfg_type {
+ struct {
+ u32 x_subsampled;
+ u32 y_subsampled;
+ } i_frame, p_frame, b_frame;
+};
+
+struct hal_vpe_color_space_conversion {
+ u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
+ u32 csc_bias[HAL_MAX_BIAS_COEFFS];
+ u32 csc_limit[HAL_MAX_LIMIT_COEFFS];
+};
+
+enum vidc_resource_id {
+ VIDC_RESOURCE_NONE,
+ VIDC_RESOURCE_OCMEM,
+ VIDC_RESOURCE_VMEM,
+ VIDC_UNUSED_RESOURCE = 0x10000000,
+};
+
+struct vidc_resource_hdr {
+ enum vidc_resource_id resource_id;
+ void *resource_handle;
+ u32 size;
+};
+
+struct vidc_buffer_addr_info {
+ enum hal_buffer buffer_type;
+ u32 buffer_size;
+ u32 num_buffers;
+ ion_phys_addr_t align_device_addr;
+ ion_phys_addr_t extradata_addr;
+ u32 extradata_size;
+ u32 response_required;
+};
+
+/* Needs to be exactly the same as hfi_buffer_info */
+struct hal_buffer_info {
+ u32 buffer_addr;
+ u32 extra_data_addr;
+};
+
+struct vidc_frame_plane_config {
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+ u32 stride;
+ u32 scan_lines;
+};
+
+struct vidc_uncompressed_frame_config {
+ struct vidc_frame_plane_config luma_plane;
+ struct vidc_frame_plane_config chroma_plane;
+};
+
+struct vidc_frame_data {
+ enum hal_buffer buffer_type;
+ ion_phys_addr_t device_addr;
+ ion_phys_addr_t extradata_addr;
+ int64_t timestamp;
+ u32 flags;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 mark_target;
+ u32 mark_data;
+ u32 clnt_data;
+ u32 extradata_size;
+};
+
+struct vidc_seq_hdr {
+ ion_phys_addr_t seq_hdr;
+ u32 seq_hdr_len;
+};
+
+enum hal_flush {
+ HAL_FLUSH_INPUT,
+ HAL_FLUSH_OUTPUT,
+ HAL_FLUSH_OUTPUT2,
+ HAL_FLUSH_ALL,
+ HAL_UNUSED_FLUSH = 0x10000000,
+};
+
+enum hal_event_type {
+ HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
+ HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+ HAL_EVENT_RELEASE_BUFFER_REFERENCE,
+ HAL_UNUSED_SEQCHG = 0x10000000,
+};
+
+enum buffer_mode_type {
+ HAL_BUFFER_MODE_STATIC = 0x001,
+ HAL_BUFFER_MODE_RING = 0x010,
+ HAL_BUFFER_MODE_DYNAMIC = 0x100,
+};
+
+struct hal_buffer_alloc_mode {
+ enum hal_buffer buffer_type;
+ enum buffer_mode_type buffer_mode;
+};
+
+enum ltr_mode {
+ HAL_LTR_MODE_DISABLE,
+ HAL_LTR_MODE_MANUAL,
+ HAL_LTR_MODE_PERIODIC,
+};
+
+struct hal_ltr_mode {
+ enum ltr_mode mode;
+ u32 count;
+ u32 trust_mode;
+};
+
+struct hal_ltr_use {
+ u32 ref_ltr;
+ u32 use_constraint;
+ u32 frames;
+};
+
+struct hal_ltr_mark {
+ u32 mark_frame;
+};
+
+struct hal_venc_perf_mode {
+ u32 mode;
+};
+
+struct hal_hybrid_hierp {
+ u32 layers;
+};
+
+struct hfi_scs_threshold {
+ u32 threshold_value;
+};
+
+struct buffer_requirements {
+ struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
+};
+
+union hal_get_property {
+ struct hal_frame_rate frame_rate;
+ struct hal_uncompressed_format_select format_select;
+ struct hal_uncompressed_plane_actual plane_actual;
+ struct hal_uncompressed_plane_actual_info plane_actual_info;
+ struct hal_uncompressed_plane_constraints plane_constraints;
+ struct hal_uncompressed_plane_actual_constraints_info
+ plane_constraints_info;
+ struct hal_extra_data_header_config extra_data_header_config;
+ struct hal_frame_size frame_size;
+ struct hal_enable enable;
+ struct hal_buffer_count_actual buffer_count_actual;
+ struct hal_extradata_enable extradata_enable;
+ struct hal_enable_picture enable_picture;
+ struct hal_multi_stream multi_stream;
+ struct hal_display_picture_buffer_count display_picture_buffer_count;
+ struct hal_mb_error_map mb_error_map;
+ struct hal_request_iframe request_iframe;
+ struct hal_bitrate bitrate;
+ struct hal_profile_level profile_level;
+ struct hal_profile_level_supported profile_level_supported;
+ struct hal_h264_entropy_control h264_entropy_control;
+ struct hal_mpeg4_time_resolution mpeg4_time_resolution;
+ struct hal_mpeg4_header_extension mpeg4_header_extension;
+ struct hal_h264_db_control h264_db_control;
+ struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff;
+ struct hal_quantization quantization;
+ struct hal_quantization_range quantization_range;
+ struct hal_intra_period intra_period;
+ struct hal_idr_period idr_period;
+ struct hal_operations operations;
+ struct hal_intra_refresh intra_refresh;
+ struct hal_multi_slice_control multi_slice_control;
+ struct hal_debug_config debug_config;
+ struct hal_batch_info batch_info;
+ struct hal_metadata_pass_through metadata_pass_through;
+ struct hal_uncompressed_format_supported uncompressed_format_supported;
+ struct hal_interlace_format_supported interlace_format_supported;
+ struct hal_properties_supported properties_supported;
+ struct hal_capability_supported capability_supported;
+ struct hal_capability_supported_info capability_supported_info;
+ struct hal_nal_stream_format_supported nal_stream_format_supported;
+ struct hal_nal_stream_format_select nal_stream_format_select;
+ struct hal_multi_view_format multi_view_format;
+ struct hal_seq_header_info seq_header_info;
+ struct hal_codec_supported codec_supported;
+ struct hal_multi_view_select multi_view_select;
+ struct hal_timestamp_scale timestamp_scale;
+ struct hal_h264_vui_timing_info h264_vui_timing_info;
+ struct hal_h264_vui_bitstream_restrc h264_vui_bitstream_restrc;
+ struct hal_preserve_text_quality preserve_text_quality;
+ struct hal_buffer_info buffer_info;
+ struct hal_buffer_alloc_mode buffer_alloc_mode;
+ struct buffer_requirements buf_req;
+};
+
+/* HAL Response */
+
+enum command_response {
+/* SYSTEM COMMANDS_DONE*/
+ VIDC_EVENT_CHANGE,
+ SYS_INIT_DONE,
+ SET_RESOURCE_DONE,
+ RELEASE_RESOURCE_DONE,
+ PING_ACK_DONE,
+ PC_PREP_DONE,
+ SYS_IDLE,
+ SYS_DEBUG,
+ SYS_WATCHDOG_TIMEOUT,
+ SYS_ERROR,
+/* SESSION COMMANDS_DONE */
+ SESSION_LOAD_RESOURCE_DONE,
+ SESSION_INIT_DONE,
+ SESSION_END_DONE,
+ SESSION_ABORT_DONE,
+ SESSION_START_DONE,
+ SESSION_STOP_DONE,
+ SESSION_ETB_DONE,
+ SESSION_FTB_DONE,
+ SESSION_FLUSH_DONE,
+ SESSION_SUSPEND_DONE,
+ SESSION_RESUME_DONE,
+ SESSION_SET_PROP_DONE,
+ SESSION_GET_PROP_DONE,
+ SESSION_PARSE_SEQ_HDR_DONE,
+ SESSION_GET_SEQ_HDR_DONE,
+ SESSION_RELEASE_BUFFER_DONE,
+ SESSION_RELEASE_RESOURCE_DONE,
+ SESSION_PROPERTY_INFO,
+ SESSION_ERROR,
+ RESPONSE_UNUSED = 0x10000000,
+};
+
+/* Command Callback structure */
+
+struct msm_vidc_cb_cmd_done {
+ u32 device_id;
+ void *session_id;
+ enum vidc_status status;
+ u32 size;
+ void *data;
+};
+
+struct msm_vidc_cb_event {
+ u32 device_id;
+ u32 session_id;
+ enum vidc_status status;
+ u32 height;
+ u32 width;
+ u32 hal_event_type;
+ ion_phys_addr_t packet_buffer;
+ ion_phys_addr_t extra_data_buffer;
+};
+
+/* Data callback structure */
+
+struct vidc_hal_ebd {
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags;
+ enum vidc_status status;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ enum hal_picture picture_type;
+ ion_phys_addr_t packet_buffer;
+ ion_phys_addr_t extra_data_buffer;
+};
+
+struct vidc_hal_fbd {
+ u32 stream_id;
+ u32 view_id;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags1;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len1;
+ u32 filled_len1;
+ u32 offset1;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_x_coord;
+ u32 start_y_coord;
+ u32 input_tag;
+ u32 input_tag1;
+ enum hal_picture picture_type;
+ ion_phys_addr_t packet_buffer1;
+ ion_phys_addr_t extra_data_buffer;
+ u32 flags2;
+ u32 alloc_len2;
+ u32 filled_len2;
+ u32 offset2;
+ ion_phys_addr_t packet_buffer2;
+ u32 flags3;
+ u32 alloc_len3;
+ u32 filled_len3;
+ u32 offset3;
+ ion_phys_addr_t packet_buffer3;
+ enum hal_buffer buffer_type;
+};
+
+struct msm_vidc_cb_data_done {
+ u32 device_id;
+ void *session_id;
+ enum vidc_status status;
+ u32 size;
+ u32 clnt_data;
+ union {
+ struct vidc_hal_ebd input_done;
+ struct vidc_hal_fbd output_done;
+ };
+};
+
+struct vidc_hal_sys_init_done {
+ u32 enc_codec_supported;
+ u32 dec_codec_supported;
+};
+
+struct vidc_hal_session_init_done {
+ struct hal_capability_supported width;
+ struct hal_capability_supported height;
+ struct hal_capability_supported mbs_per_frame;
+ struct hal_capability_supported mbs_per_sec;
+ struct hal_capability_supported frame_rate;
+ struct hal_capability_supported scale_x;
+ struct hal_capability_supported scale_y;
+ struct hal_capability_supported bitrate;
+ struct hal_capability_supported hier_p;
+ struct hal_capability_supported ltr_count;
+ struct hal_capability_supported secure_output2_threshold;
+ struct hal_uncompressed_format_supported uncomp_format;
+ struct hal_interlace_format_supported HAL_format;
+ struct hal_nal_stream_format_supported nal_stream_format;
+ struct hal_profile_level_supported profile_level;
+ /*allocate and released memory for above.*/
+ struct hal_intra_refresh intra_refresh;
+ struct hal_seq_header_info seq_hdr_info;
+ enum buffer_mode_type alloc_mode_out;
+};
+
+enum msm_vidc_hfi_type {
+ VIDC_HFI_VENUS,
+ VIDC_HFI_Q6,
+};
+
+enum fw_info {
+ FW_BASE_ADDRESS,
+ FW_REGISTER_BASE,
+ FW_REGISTER_SIZE,
+ FW_IRQ,
+ FW_INFO_MAX,
+};
+
+enum msm_vidc_thermal_level {
+ VIDC_THERMAL_NORMAL = 0,
+ VIDC_THERMAL_LOW,
+ VIDC_THERMAL_HIGH,
+ VIDC_THERMAL_CRITICAL
+};
+
+enum vidc_bus_vote_data_session {
+ VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0,
+ /* No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL
+ * describe the enumerations e.g.:
+ *
+ * enum vidc_bus_vote_data_session_type h264_decoder_session =
+ * VIDC_VOTE_DATA_SESSION_VAL(HAL_VIDEO_CODEC_H264,
+ * HAL_VIDEO_DOMAIN_DECODER);
+ */
+};
+
+/* Careful modifying VIDC_VOTE_DATA_SESSION_VAL().
+ *
+ * This macro assigns two bits to each codec: the lower bit denoting the codec
+ * type, and the higher bit denoting session type. */
+static inline enum vidc_bus_vote_data_session VIDC_VOTE_DATA_SESSION_VAL(
+ enum hal_video_codec c, enum hal_domain d) {
+ if (d != HAL_VIDEO_DOMAIN_ENCODER && d != HAL_VIDEO_DOMAIN_DECODER)
+ return VIDC_BUS_VOTE_DATA_SESSION_INVALID;
+
+ return (1 << ilog2(c) * 2) | ((d - 1) << (ilog2(c) * 2 + 1));
+}
+
+struct vidc_bus_vote_data {
+ enum vidc_bus_vote_data_session session;
+ int load;
+};
+
+#define call_hfi_op(q, op, args...) \
+ (((q) && (q)->op) ? ((q)->op(args)) : 0)
+
+struct hfi_device {
+ void *hfi_device_data;
+
+ /*Add function pointers for all the hfi functions below*/
+ int (*core_init)(void *device);
+ int (*core_release)(void *device);
+ int (*core_pc_prep)(void *device);
+ int (*core_ping)(void *device);
+ int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
+ void *(*session_init)(void *device, void *session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type);
+ int (*session_end)(void *session);
+ int (*session_abort)(void *session);
+ int (*session_set_buffers)(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_release_buffers)(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_load_res)(void *sess);
+ int (*session_release_res)(void *sess);
+ int (*session_start)(void *sess);
+ int (*session_stop)(void *sess);
+ int (*session_etb)(void *sess,
+ struct vidc_frame_data *input_frame);
+ int (*session_ftb)(void *sess,
+ struct vidc_frame_data *output_frame);
+ int (*session_parse_seq_hdr)(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_seq_hdr)(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_buf_req)(void *sess);
+ int (*session_flush)(void *sess, enum hal_flush flush_mode);
+ int (*session_set_property)(void *sess, enum hal_property ptype,
+ void *pdata);
+ int (*session_get_property)(void *sess, enum hal_property ptype);
+ int (*scale_clocks)(void *dev, int load, int codecs_enabled);
+ int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data,
+ int num_data);
+ int (*unvote_bus)(void *dev);
+ int (*load_fw)(void *dev);
+ void (*unload_fw)(void *dev);
+ int (*resurrect_fw)(void *dev);
+ int (*get_fw_info)(void *dev, enum fw_info info);
+ int (*get_stride_scanline)(int color_fmt, int width,
+ int height, int *stride, int *scanlines);
+ int (*session_clean)(void *sess);
+ int (*get_core_capabilities)(void);
+ int (*power_enable)(void *dev);
+ int (*suspend)(void *dev);
+ unsigned long (*get_core_clock_rate)(void *dev);
+ enum hal_default_properties (*get_default_properties)(void *dev);
+};
+
+typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
+ void *data);
+typedef void (*msm_vidc_callback) (u32 response, void *callback);
+
+void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
+ struct msm_vidc_platform_resources *res,
+ hfi_cmd_response_callback callback);
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+ struct hfi_device *hdev);
+
+
+#endif /*__VIDC_HFI_API_H__ */
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
new file mode 100644
index 000000000000..cf06b8970527
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -0,0 +1,1075 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef __H_VIDC_HFI_HELPER_H__
+#define __H_VIDC_HFI_HELPER_H__
+
+#define HFI_COMMON_BASE (0)
+#define HFI_OX_BASE (0x01000000)
+
+#define HFI_VIDEO_DOMAIN_ENCODER (HFI_COMMON_BASE + 0x1)
+#define HFI_VIDEO_DOMAIN_DECODER (HFI_COMMON_BASE + 0x2)
+#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x4)
+#define HFI_VIDEO_DOMAIN_MBI (HFI_COMMON_BASE + 0x8)
+
+#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0)
+#define HFI_DOMAIN_BASE_VDEC (HFI_COMMON_BASE + 0x01000000)
+#define HFI_DOMAIN_BASE_VENC (HFI_COMMON_BASE + 0x02000000)
+#define HFI_DOMAIN_BASE_VPE (HFI_COMMON_BASE + 0x03000000)
+
+#define HFI_VIDEO_ARCH_OX (HFI_COMMON_BASE + 0x1)
+
+#define HFI_ARCH_COMMON_OFFSET (0)
+#define HFI_ARCH_OX_OFFSET (0x00200000)
+
+#define HFI_CMD_START_OFFSET (0x00010000)
+#define HFI_MSG_START_OFFSET (0x00020000)
+
+#define HFI_ERR_NONE HFI_COMMON_BASE
+#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_INVALID_PARAMETER (HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_MAX_SESSIONS_REACHED (HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_UNSUPPORTED_CODEC (HFI_COMMON_BASE + 0x6)
+#define HFI_ERR_SYS_SESSION_IN_USE (HFI_COMMON_BASE + 0x7)
+#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE (HFI_COMMON_BASE + 0x8)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x9)
+
+#define HFI_ERR_SESSION_FATAL (HFI_COMMON_BASE + 0x1001)
+#define HFI_ERR_SESSION_INVALID_PARAMETER (HFI_COMMON_BASE + 0x1002)
+#define HFI_ERR_SESSION_BAD_POINTER (HFI_COMMON_BASE + 0x1003)
+#define HFI_ERR_SESSION_INVALID_SESSION_ID (HFI_COMMON_BASE + 0x1004)
+#define HFI_ERR_SESSION_INVALID_STREAM_ID (HFI_COMMON_BASE + 0x1005)
+#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION \
+ (HFI_COMMON_BASE + 0x1006)
+#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY (HFI_COMMON_BASE + 0x1007)
+
+#define HFI_ERR_SESSION_UNSUPPORTED_SETTING (HFI_COMMON_BASE + 0x1008)
+
+#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x1009)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED \
+ (HFI_COMMON_BASE + 0x100A)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT (HFI_COMMON_BASE + 0x100B)
+#define HFI_ERR_SESSION_ENC_OVERFLOW (HFI_COMMON_BASE + 0x100C)
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM (HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_CMDSIZE (HFI_COMMON_BASE + 0x100E)
+#define HFI_ERR_SESSION_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x100F)
+#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE (HFI_COMMON_BASE + 0x1010)
+#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL (HFI_COMMON_BASE + 0x1011)
+#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR (HFI_COMMON_BASE + 0x1012)
+#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED (HFI_COMMON_BASE + 0x1013)
+
+#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2)
+
+#define HFI_VIDEO_CODEC_H264 0x00000002
+#define HFI_VIDEO_CODEC_H263 0x00000004
+#define HFI_VIDEO_CODEC_MPEG1 0x00000008
+#define HFI_VIDEO_CODEC_MPEG2 0x00000010
+#define HFI_VIDEO_CODEC_MPEG4 0x00000020
+#define HFI_VIDEO_CODEC_DIVX_311 0x00000040
+#define HFI_VIDEO_CODEC_DIVX 0x00000080
+#define HFI_VIDEO_CODEC_VC1 0x00000100
+#define HFI_VIDEO_CODEC_SPARK 0x00000200
+#define HFI_VIDEO_CODEC_VP8 0x00001000
+#define HFI_VIDEO_CODEC_HEVC 0x00002000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID 0x00004000
+
+#define HFI_H264_PROFILE_BASELINE 0x00000001
+#define HFI_H264_PROFILE_MAIN 0x00000002
+#define HFI_H264_PROFILE_HIGH 0x00000004
+#define HFI_H264_PROFILE_STEREO_HIGH 0x00000008
+#define HFI_H264_PROFILE_MULTIVIEW_HIGH 0x00000010
+#define HFI_H264_PROFILE_CONSTRAINED_BASE 0x00000020
+#define HFI_H264_PROFILE_CONSTRAINED_HIGH 0x00000040
+
+#define HFI_H264_LEVEL_1 0x00000001
+#define HFI_H264_LEVEL_1b 0x00000002
+#define HFI_H264_LEVEL_11 0x00000004
+#define HFI_H264_LEVEL_12 0x00000008
+#define HFI_H264_LEVEL_13 0x00000010
+#define HFI_H264_LEVEL_2 0x00000020
+#define HFI_H264_LEVEL_21 0x00000040
+#define HFI_H264_LEVEL_22 0x00000080
+#define HFI_H264_LEVEL_3 0x00000100
+#define HFI_H264_LEVEL_31 0x00000200
+#define HFI_H264_LEVEL_32 0x00000400
+#define HFI_H264_LEVEL_4 0x00000800
+#define HFI_H264_LEVEL_41 0x00001000
+#define HFI_H264_LEVEL_42 0x00002000
+#define HFI_H264_LEVEL_5 0x00004000
+#define HFI_H264_LEVEL_51 0x00008000
+#define HFI_H264_LEVEL_52 0x00010000
+
+#define HFI_H263_PROFILE_BASELINE 0x00000001
+
+#define HFI_H263_LEVEL_10 0x00000001
+#define HFI_H263_LEVEL_20 0x00000002
+#define HFI_H263_LEVEL_30 0x00000004
+#define HFI_H263_LEVEL_40 0x00000008
+#define HFI_H263_LEVEL_45 0x00000010
+#define HFI_H263_LEVEL_50 0x00000020
+#define HFI_H263_LEVEL_60 0x00000040
+#define HFI_H263_LEVEL_70 0x00000080
+
+#define HFI_MPEG2_PROFILE_SIMPLE 0x00000001
+#define HFI_MPEG2_PROFILE_MAIN 0x00000002
+#define HFI_MPEG2_PROFILE_422 0x00000004
+#define HFI_MPEG2_PROFILE_SNR 0x00000008
+#define HFI_MPEG2_PROFILE_SPATIAL 0x00000010
+#define HFI_MPEG2_PROFILE_HIGH 0x00000020
+
+#define HFI_MPEG2_LEVEL_LL 0x00000001
+#define HFI_MPEG2_LEVEL_ML 0x00000002
+#define HFI_MPEG2_LEVEL_H14 0x00000004
+#define HFI_MPEG2_LEVEL_HL 0x00000008
+
+#define HFI_MPEG4_PROFILE_SIMPLE 0x00000001
+#define HFI_MPEG4_PROFILE_ADVANCEDSIMPLE 0x00000002
+
+#define HFI_MPEG4_LEVEL_0 0x00000001
+#define HFI_MPEG4_LEVEL_0b 0x00000002
+#define HFI_MPEG4_LEVEL_1 0x00000004
+#define HFI_MPEG4_LEVEL_2 0x00000008
+#define HFI_MPEG4_LEVEL_3 0x00000010
+#define HFI_MPEG4_LEVEL_4 0x00000020
+#define HFI_MPEG4_LEVEL_4a 0x00000040
+#define HFI_MPEG4_LEVEL_5 0x00000080
+#define HFI_MPEG4_LEVEL_6 0x00000100
+#define HFI_MPEG4_LEVEL_7 0x00000200
+#define HFI_MPEG4_LEVEL_8 0x00000400
+#define HFI_MPEG4_LEVEL_9 0x00000800
+#define HFI_MPEG4_LEVEL_3b 0x00001000
+
+#define HFI_VC1_PROFILE_SIMPLE 0x00000001
+#define HFI_VC1_PROFILE_MAIN 0x00000002
+#define HFI_VC1_PROFILE_ADVANCED 0x00000004
+
+#define HFI_VC1_LEVEL_LOW 0x00000001
+#define HFI_VC1_LEVEL_MEDIUM 0x00000002
+#define HFI_VC1_LEVEL_HIGH 0x00000004
+#define HFI_VC1_LEVEL_0 0x00000008
+#define HFI_VC1_LEVEL_1 0x00000010
+#define HFI_VC1_LEVEL_2 0x00000020
+#define HFI_VC1_LEVEL_3 0x00000040
+#define HFI_VC1_LEVEL_4 0x00000080
+
+#define HFI_VPX_PROFILE_SIMPLE 0x00000001
+#define HFI_VPX_PROFILE_ADVANCED 0x00000002
+#define HFI_VPX_PROFILE_VERSION_0 0x00000004
+#define HFI_VPX_PROFILE_VERSION_1 0x00000008
+#define HFI_VPX_PROFILE_VERSION_2 0x00000010
+#define HFI_VPX_PROFILE_VERSION_3 0x00000020
+
+#define HFI_DIVX_FORMAT_4 (HFI_COMMON_BASE + 0x1)
+#define HFI_DIVX_FORMAT_5 (HFI_COMMON_BASE + 0x2)
+#define HFI_DIVX_FORMAT_6 (HFI_COMMON_BASE + 0x3)
+
+#define HFI_DIVX_PROFILE_QMOBILE 0x00000001
+#define HFI_DIVX_PROFILE_MOBILE 0x00000002
+#define HFI_DIVX_PROFILE_MT 0x00000004
+#define HFI_DIVX_PROFILE_HT 0x00000008
+#define HFI_DIVX_PROFILE_HD 0x00000010
+
+#define HFI_HEVC_PROFILE_MAIN 0x00000001
+#define HFI_HEVC_PROFILE_MAIN10 0x00000002
+#define HFI_HEVC_PROFILE_MAIN_STILL_PIC 0x00000004
+
+#define HFI_HEVC_LEVEL_1 0x00000001
+#define HFI_HEVC_LEVEL_2 0x00000002
+#define HFI_HEVC_LEVEL_21 0x00000004
+#define HFI_HEVC_LEVEL_3 0x00000008
+#define HFI_HEVC_LEVEL_31 0x00000010
+#define HFI_HEVC_LEVEL_4 0x00000020
+#define HFI_HEVC_LEVEL_41 0x00000040
+#define HFI_HEVC_LEVEL_5 0x00000080
+#define HFI_HEVC_LEVEL_51 0x00000100
+#define HFI_HEVC_LEVEL_52 0x00000200
+#define HFI_HEVC_LEVEL_6 0x00000400
+#define HFI_HEVC_LEVEL_61 0x00000800
+#define HFI_HEVC_LEVEL_62 0x00001000
+
+#define HFI_HEVC_TIER_MAIN 0x1
+#define HFI_HEVC_TIER_HIGH0 0x2
+
+#define HFI_BUFFER_INPUT (HFI_COMMON_BASE + 0x1)
+#define HFI_BUFFER_OUTPUT (HFI_COMMON_BASE + 0x2)
+#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3)
+#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_PERSIST_1 (HFI_COMMON_BASE + 0x5)
+
+#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
+
+struct hfi_buffer_info {
+ u32 buffer_addr;
+ u32 extra_data_addr;
+};
+
+#define HFI_PROPERTY_SYS_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_DEBUG_CONFIG \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x001)
+#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x002)
+#define HFI_PROPERTY_SYS_CONFIG_VCODEC_CLKFREQ \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x003)
+#define HFI_PROPERTY_SYS_IDLE_INDICATOR \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x004)
+#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x005)
+#define HFI_PROPERTY_SYS_IMAGE_VERSION \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x006)
+#define HFI_PROPERTY_SYS_CONFIG_COVERAGE \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_FRAME_SIZE \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
+
+#define HFI_PROPERTY_CONFIG_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
+#define HFI_PROPERTY_CONFIG_FRAME_RATE \
+ (HFI_PROPERTY_CONFIG_COMMON_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VDEC_COMMON_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2 \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x003)
+
+#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000)
+
+#define HFI_PROPERTY_PARAM_VENC_COMMON_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VENC_OPEN_GOP \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F)
+#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
+#define HFI_PROPERTY_PARAM_VENC_ADVANCED \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012)
+#define HFI_PROPERTY_PARAM_VENC_H264_SPS_ID \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014)
+#define HFI_PROPERTY_PARAM_VENC_H264_PPS_ID \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015)
+#define HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x016)
+#define HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x017)
+#define HFI_PROPERTY_PARAM_VENC_NUMREF \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018)
+#define HFI_PROPERTY_PARAM_VENC_MULTIREF_P \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
+#define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VENC_LTRMODE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C)
+#define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
+#define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
+#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021)
+#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x023)
+#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026)
+#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x027)
+#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028)
+#define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029)
+#define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C)
+#define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02F)
+
+#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
+#define HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
+#define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009)
+#define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B)
+#define HFI_PROPERTY_CONFIG_VENC_LTRPERIOD \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00C)
+#define HFI_PROPERTY_CONFIG_VENC_PERF_MODE \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00E)
+
+#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
+#define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE \
+ (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS \
+ (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
+
+struct hfi_bitrate {
+ u32 bit_rate;
+ u32 layer_id;
+};
+
+#define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1)
+#define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2)
+#define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3)
+#define HFI_CAPABILITY_MBS_PER_SECOND (HFI_COMMON_BASE + 0x4)
+#define HFI_CAPABILITY_FRAMERATE (HFI_COMMON_BASE + 0x5)
+#define HFI_CAPABILITY_SCALE_X (HFI_COMMON_BASE + 0x6)
+#define HFI_CAPABILITY_SCALE_Y (HFI_COMMON_BASE + 0x7)
+#define HFI_CAPABILITY_BITRATE (HFI_COMMON_BASE + 0x8)
+#define HFI_CAPABILITY_BFRAME (HFI_COMMON_BASE + 0x9)
+#define HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x10)
+#define HFI_CAPABILITY_ENC_LTR_COUNT (HFI_COMMON_BASE + 0x11)
+#define HFI_CAPABILITY_CP_OUTPUT2_THRESH (HFI_COMMON_BASE + 0x12)
+#define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x15)
+
+struct hfi_capability_supported {
+ u32 capability_type;
+ u32 min;
+ u32 max;
+ u32 step_size;
+};
+
+struct hfi_capability_supported_info {
+ u32 num_capabilities;
+ struct hfi_capability_supported rg_data[1];
+};
+
+#define HFI_DEBUG_MSG_LOW 0x00000001
+#define HFI_DEBUG_MSG_MEDIUM 0x00000002
+#define HFI_DEBUG_MSG_HIGH 0x00000004
+#define HFI_DEBUG_MSG_ERROR 0x00000008
+#define HFI_DEBUG_MSG_FATAL 0x00000010
+#define HFI_DEBUG_MSG_PERF 0x00000020
+
+#define HFI_DEBUG_MODE_QUEUE 0x00000001
+#define HFI_DEBUG_MODE_QDSS 0x00000002
+
+struct hfi_debug_config {
+ u32 debug_config;
+ u32 debug_mode;
+};
+
+struct hfi_enable {
+ int enable;
+};
+
+#define HFI_H264_DB_MODE_DISABLE (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY \
+ (HFI_COMMON_BASE + 0x2)
+#define HFI_H264_DB_MODE_ALL_BOUNDARY (HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_db_control {
+ u32 mode;
+ int slice_alpha_offset;
+ int slice_beta_offset;
+};
+
+#define HFI_H264_ENTROPY_CAVLC (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_ENTROPY_CABAC (HFI_COMMON_BASE + 0x2)
+
+#define HFI_H264_CABAC_MODEL_0 (HFI_COMMON_BASE + 0x1)
+#define HFI_H264_CABAC_MODEL_1 (HFI_COMMON_BASE + 0x2)
+#define HFI_H264_CABAC_MODEL_2 (HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_entropy_control {
+ u32 entropy_mode;
+ u32 cabac_model;
+};
+
+struct hfi_frame_rate {
+ u32 buffer_type;
+ u32 frame_rate;
+};
+
+#define HFI_INTRA_REFRESH_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_INTRA_REFRESH_CYCLIC (HFI_COMMON_BASE + 0x2)
+#define HFI_INTRA_REFRESH_ADAPTIVE (HFI_COMMON_BASE + 0x3)
+#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE (HFI_COMMON_BASE + 0x4)
+#define HFI_INTRA_REFRESH_RANDOM (HFI_COMMON_BASE + 0x5)
+
+struct hfi_intra_refresh {
+ u32 mode;
+ u32 air_mbs;
+ u32 air_ref;
+ u32 cir_mbs;
+};
+
+struct hfi_idr_period {
+ u32 idr_period;
+};
+
+struct hfi_operations_type {
+ u32 rotation;
+ u32 flip;
+};
+
+struct hfi_max_num_b_frames {
+ u32 max_num_b_frames;
+};
+
+struct hfi_vc1e_perf_cfg_type {
+ u32 search_range_x_subsampled[3];
+ u32 search_range_y_subsampled[3];
+};
+
+struct hfi_conceal_color {
+ u32 conceal_color;
+};
+
+struct hfi_intra_period {
+ u32 pframes;
+ u32 bframes;
+};
+
+struct hfi_mpeg4_header_extension {
+ u32 header_extension;
+};
+
+struct hfi_mpeg4_time_resolution {
+ u32 time_increment_resolution;
+};
+
+struct hfi_multi_stream {
+ u32 buffer_type;
+ u32 enable;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_multi_view_format {
+ u32 views;
+ u32 rg_view_order[1];
+};
+
+#define HFI_MULTI_SLICE_OFF (HFI_COMMON_BASE + 0x1)
+#define HFI_MULTI_SLICE_BY_MB_COUNT (HFI_COMMON_BASE + 0x2)
+#define HFI_MULTI_SLICE_BY_BYTE_COUNT (HFI_COMMON_BASE + 0x3)
+#define HFI_MULTI_SLICE_GOB (HFI_COMMON_BASE + 0x4)
+
+struct hfi_multi_slice_control {
+ u32 multi_slice;
+ u32 slice_size;
+};
+
+#define HFI_NAL_FORMAT_STARTCODES 0x00000001
+#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER 0x00000002
+#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH 0x00000004
+#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH 0x00000008
+#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH 0x00000010
+
+struct hfi_nal_stream_format_supported {
+ u32 nal_stream_format_supported;
+};
+
+struct hfi_nal_stream_format_select {
+ u32 nal_stream_format_select;
+};
+#define HFI_PICTURE_TYPE_I 0x01
+#define HFI_PICTURE_TYPE_P 0x02
+#define HFI_PICTURE_TYPE_B 0x04
+#define HFI_PICTURE_TYPE_IDR 0x08
+
+struct hfi_profile_level {
+ u32 profile;
+ u32 level;
+};
+
+struct hfi_profile_level_supported {
+ u32 profile_count;
+ struct hfi_profile_level rg_profile_level[1];
+};
+
+struct hfi_quality_vs_speed {
+ u32 quality_vs_speed;
+};
+
+struct hfi_quantization {
+ u32 qp_i;
+ u32 qp_p;
+ u32 qp_b;
+ u32 layer_id;
+};
+
+struct hfi_initial_quantization {
+ u32 qp_i;
+ u32 qp_p;
+ u32 qp_b;
+ u32 init_qp_enable;
+};
+
+struct hfi_quantization_range {
+ u32 min_qp;
+ u32 max_qp;
+ u32 layer_id;
+};
+
+#define HFI_LTR_MODE_DISABLE 0x0
+#define HFI_LTR_MODE_MANUAL 0x1
+#define HFI_LTR_MODE_PERIODIC 0x2
+
+struct hfi_ltr_mode {
+ u32 ltr_mode;
+ u32 ltr_count;
+ u32 trust_mode;
+};
+
+struct hfi_ltr_use {
+ u32 ref_ltr;
+ u32 use_constrnt;
+ u32 frames;
+};
+
+struct hfi_ltr_mark {
+ u32 mark_frame;
+};
+
+struct hfi_frame_size {
+ u32 buffer_type;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_h264_vui_timing_info {
+ u32 enable;
+ u32 fixed_frame_rate;
+ u32 time_scale;
+};
+
+/* Base Offset for UBWC color formats */
+#define HFI_COLOR_FORMAT_UBWC_BASE (0x8000)
+/* Base Offset for 10-bit color formats */
+#define HFI_COLOR_FORMAT_10_BIT_BASE (0x4000)
+
+#define HFI_COLOR_FORMAT_MONOCHROME (HFI_COMMON_BASE + 0x1)
+#define HFI_COLOR_FORMAT_NV12 (HFI_COMMON_BASE + 0x2)
+#define HFI_COLOR_FORMAT_NV21 (HFI_COMMON_BASE + 0x3)
+#define HFI_COLOR_FORMAT_NV12_4x4TILE (HFI_COMMON_BASE + 0x4)
+#define HFI_COLOR_FORMAT_NV21_4x4TILE (HFI_COMMON_BASE + 0x5)
+#define HFI_COLOR_FORMAT_YUYV (HFI_COMMON_BASE + 0x6)
+#define HFI_COLOR_FORMAT_YVYU (HFI_COMMON_BASE + 0x7)
+#define HFI_COLOR_FORMAT_UYVY (HFI_COMMON_BASE + 0x8)
+#define HFI_COLOR_FORMAT_VYUY (HFI_COMMON_BASE + 0x9)
+#define HFI_COLOR_FORMAT_RGB565 (HFI_COMMON_BASE + 0xA)
+#define HFI_COLOR_FORMAT_BGR565 (HFI_COMMON_BASE + 0xB)
+#define HFI_COLOR_FORMAT_RGB888 (HFI_COMMON_BASE + 0xC)
+#define HFI_COLOR_FORMAT_BGR888 (HFI_COMMON_BASE + 0xD)
+#define HFI_COLOR_FORMAT_YUV444 (HFI_COMMON_BASE + 0xE)
+#define HFI_COLOR_FORMAT_RGBA8888 (HFI_COMMON_BASE + 0x10)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10 \
+ (HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_NV12_UBWC \
+ (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC \
+ (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_YUV420_TP10)
+
+#define HFI_COLOR_FORMAT_RGBA8888_UBWC \
+ (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_RGBA8888)
+
+#define HFI_MAX_MATRIX_COEFFS 9
+#define HFI_MAX_BIAS_COEFFS 3
+#define HFI_MAX_LIMIT_COEFFS 6
+
+struct hfi_uncompressed_format_select {
+ u32 buffer_type;
+ u32 format;
+};
+
+struct hfi_uncompressed_format_supported {
+ u32 buffer_type;
+ u32 format_entries;
+ u32 rg_format_info[1];
+};
+
+struct hfi_uncompressed_plane_actual {
+ int actual_stride;
+ u32 actual_plane_buffer_height;
+};
+
+struct hfi_uncompressed_plane_actual_info {
+ u32 buffer_type;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_constraints {
+ u32 stride_multiples;
+ u32 max_stride;
+ u32 min_plane_buffer_height_multiple;
+ u32 buffer_alignment;
+};
+
+struct hfi_uncompressed_plane_info {
+ u32 format;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_codec_supported {
+ u32 decoder_codec_supported;
+ u32 encoder_codec_supported;
+};
+
+struct hfi_properties_supported {
+ u32 num_properties;
+ u32 rg_properties[1];
+};
+
+struct hfi_vpe_color_space_conversion {
+ u32 csc_matrix[HFI_MAX_MATRIX_COEFFS];
+ u32 csc_bias[HFI_MAX_BIAS_COEFFS];
+ u32 csc_limit[HFI_MAX_LIMIT_COEFFS];
+};
+
+#define HFI_ROTATE_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_ROTATE_90 (HFI_COMMON_BASE + 0x2)
+#define HFI_ROTATE_180 (HFI_COMMON_BASE + 0x3)
+#define HFI_ROTATE_270 (HFI_COMMON_BASE + 0x4)
+
+#define HFI_FLIP_NONE (HFI_COMMON_BASE + 0x1)
+#define HFI_FLIP_HORIZONTAL (HFI_COMMON_BASE + 0x2)
+#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x3)
+
+struct hfi_operations {
+ u32 rotate;
+ u32 flip;
+};
+
+#define HFI_RESOURCE_OCMEM 0x00000001
+
+struct hfi_resource_ocmem {
+ u32 size;
+ u32 mem;
+};
+
+struct hfi_resource_ocmem_requirement {
+ u32 session_domain;
+ u32 width;
+ u32 height;
+ u32 size;
+};
+
+struct hfi_resource_ocmem_requirement_info {
+ u32 num_entries;
+ struct hfi_resource_ocmem_requirement rg_requirements[1];
+};
+
+struct hfi_property_sys_image_version_info_type {
+ u32 string_size;
+ u8 str_image_version[1];
+};
+
+struct hfi_venc_config_advanced {
+ u8 pipe2d;
+ u8 hw_mode;
+ u8 low_delay_enforce;
+ u8 worker_vppsg_delay;
+ int close_gop;
+ int h264_constrain_intra_pred;
+ int h264_transform_8x8_flag;
+ int mpeg4_qpel_enable;
+ int multi_refp_en;
+ int qmatrix_en;
+ u8 vpp_info_packet_mode;
+ u8 ref_tile_mode;
+ u8 bitstream_flush_mode;
+ u32 vppsg_vspap_fb_sync_delay;
+ u32 rc_initial_delay;
+ u32 peak_bitrate_constraint;
+ u32 ds_display_frame_width;
+ u32 ds_display_frame_height;
+ u32 perf_tune_param_ptr;
+ u32 input_x_offset;
+ u32 input_y_offset;
+ u32 input_roi_width;
+ u32 input_roi_height;
+ u32 vsp_fifo_dma_sel;
+ u32 h264_num_ref_frames;
+};
+
+struct hfi_vbv_hrd_bufsize {
+ u32 buffer_size;
+};
+
+struct hfi_codec_mask_supported {
+ u32 codecs;
+ u32 video_domains;
+};
+
+struct hfi_seq_header_info {
+ u32 max_hader_len;
+};
+struct hfi_aspect_ratio {
+ u32 aspect_width;
+ u32 aspect_height;
+};
+#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM (0)
+#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE (1)
+#define HFI_MVC_BUFFER_LAYOUT_SEQ (2)
+struct hfi_mvc_buffer_layout_descp_type {
+ u32 layout_type;
+ u32 bright_view_first;
+ u32 ngap;
+};
+
+
+#define HFI_CMD_SYS_COMMON_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
+ + 0x0000)
+#define HFI_CMD_SYS_INIT (HFI_CMD_SYS_COMMON_START + 0x001)
+#define HFI_CMD_SYS_PC_PREP (HFI_CMD_SYS_COMMON_START + 0x002)
+#define HFI_CMD_SYS_SET_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x003)
+#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004)
+#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x005)
+#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x006)
+#define HFI_CMD_SYS_SESSION_INIT (HFI_CMD_SYS_COMMON_START + 0x007)
+#define HFI_CMD_SYS_SESSION_END (HFI_CMD_SYS_COMMON_START + 0x008)
+#define HFI_CMD_SYS_SET_BUFFERS (HFI_CMD_SYS_COMMON_START + 0x009)
+#define HFI_CMD_SYS_TEST_START (HFI_CMD_SYS_COMMON_START + 0x100)
+
+#define HFI_CMD_SESSION_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \
+ HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_SET_PROPERTY \
+ (HFI_CMD_SESSION_COMMON_START + 0x001)
+#define HFI_CMD_SESSION_SET_BUFFERS \
+ (HFI_CMD_SESSION_COMMON_START + 0x002)
+#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER \
+ (HFI_CMD_SESSION_COMMON_START + 0x003)
+
+#define HFI_MSG_SYS_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \
+ HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_SYS_COMMON_START + 0x2)
+#define HFI_MSG_SYS_RELEASE_RESOURCE (HFI_MSG_SYS_COMMON_START + 0x3)
+#define HFI_MSG_SYS_DEBUG (HFI_MSG_SYS_COMMON_START + 0x4)
+#define HFI_MSG_SYS_SESSION_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x6)
+#define HFI_MSG_SYS_SESSION_END_DONE (HFI_MSG_SYS_COMMON_START + 0x7)
+#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_COMMON_START + 0x8)
+#define HFI_MSG_SYS_COV (HFI_MSG_SYS_COMMON_START + 0x9)
+#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_COMMON_START + 0xA)
+
+#define HFI_MSG_SESSION_COMMON_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \
+ HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_SESSION_COMMON_START + 0x1)
+#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE \
+ (HFI_MSG_SESSION_COMMON_START + 0x2)
+
+#define HFI_CMD_SYS_TEST_SSR (HFI_CMD_SYS_TEST_START + 0x1)
+#define HFI_TEST_SSR_SW_ERR_FATAL 0x1
+#define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2
+#define HFI_TEST_SSR_HW_WDOG_IRQ 0x3
+
+struct vidc_hal_cmd_pkt_hdr {
+ u32 size;
+ u32 packet_type;
+};
+
+struct vidc_hal_msg_pkt_hdr {
+ u32 size;
+ u32 packet;
+};
+
+struct vidc_hal_session_cmd_pkt {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_init_packet {
+ u32 size;
+ u32 packet_type;
+ u32 arch_type;
+};
+
+struct hfi_cmd_sys_pc_prep_packet {
+ u32 size;
+ u32 packet_type;
+};
+
+struct hfi_cmd_sys_set_resource_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_handle;
+ u32 resource_type;
+ u32 rg_resource_data[1];
+};
+
+struct hfi_cmd_sys_release_resource_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_type;
+ u32 resource_handle;
+};
+
+struct hfi_cmd_sys_set_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_get_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_session_init_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 session_domain;
+ u32 session_codec;
+};
+
+struct hfi_cmd_sys_session_end_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_set_buffers_packet {
+ u32 size;
+ u32 packet_type;
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 num_buffers;
+ u32 rg_buffer_addr[1];
+};
+
+struct hfi_cmd_session_set_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[0];
+};
+
+struct hfi_cmd_session_set_buffers_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 extra_data_size;
+ u32 min_buffer_size;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_get_sequence_header_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_len;
+ u32 packet_buffer;
+};
+
+struct hfi_msg_event_notify_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 event_id;
+ u32 event_data1;
+ u32 event_data2;
+ u32 rg_ext_event_data[1];
+};
+
+struct hfi_msg_release_buffer_ref_event_packet {
+ u32 packet_buffer;
+ u32 extra_data_buffer;
+ u32 output_tag;
+};
+
+struct hfi_msg_sys_init_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_pc_prep_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_release_resource_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 resource_handle;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_session_init_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_end_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_get_sequence_header_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 header_len;
+ u32 sequence_header;
+};
+
+struct hfi_msg_sys_debug_packet {
+ u32 size;
+ u32 packet_type;
+ u32 msg_type;
+ u32 msg_size;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u8 rg_msg_data[1];
+};
+
+struct hfi_msg_sys_coverage_packet {
+ u32 size;
+ u32 packet_type;
+ u32 msg_size;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u8 rg_msg_data[1];
+};
+
+enum HFI_VENUS_QTBL_STATUS {
+ HFI_VENUS_QTBL_DISABLED = 0x00,
+ HFI_VENUS_QTBL_ENABLED = 0x01,
+ HFI_VENUS_QTBL_INITIALIZING = 0x02,
+ HFI_VENUS_QTBL_DEINITIALIZING = 0x03
+};
+
+enum HFI_VENUS_CTRL_INIT_STATUS {
+ HFI_VENUS_CTRL_NOT_INIT = 0x0,
+ HFI_VENUS_CTRL_READY = 0x1,
+ HFI_VENUS_CTRL_ERROR_FATAL = 0x2
+};
+
+struct hfi_sfr_struct {
+ u32 bufSize;
+ u8 rg_data[1];
+};
+
+struct hfi_cmd_sys_test_ssr_packet {
+ u32 size;
+ u32 packet_type;
+ u32 trigger_type;
+};
+#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
new file mode 100644
index 000000000000..337291b0042f
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -0,0 +1,191 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef __VIDC_HFI_IO_H__
+#define __VIDC_HFI_IO_H__
+
+#include <linux/io.h>
+
+#define VENUS_VCODEC_SS_CLOCK_HALT 0x0000000C
+#define VENUS_VPP_CORE_SW_RESET 0x00042004
+#define VENUS_VPP_CTRL_CTRL_RESET 0x00041008
+
+#define VIDC_VBIF_BASE_OFFS 0x00080000
+#define VIDC_VBIF_VERSION (VIDC_VBIF_BASE_OFFS + 0x00)
+#define VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST \
+ (VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST \
+ (VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB \
+ (VIDC_VBIF_BASE_OFFS + 0x124)
+
+#define VIDC_CPU_BASE_OFFS 0x000C0000
+#define VIDC_CPU_CS_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x00012000)
+#define VIDC_CPU_IC_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x0001F000)
+
+#define VIDC_CPU_CS_REMAP_OFFS (VIDC_CPU_CS_BASE_OFFS + 0x00)
+#define VIDC_CPU_CS_TIMER_CONTROL (VIDC_CPU_CS_BASE_OFFS + 0x04)
+#define VIDC_CPU_CS_A2HSOFTINTEN (VIDC_CPU_CS_BASE_OFFS + 0x10)
+#define VIDC_CPU_CS_A2HSOFTINTENCLR (VIDC_CPU_CS_BASE_OFFS + 0x14)
+#define VIDC_CPU_CS_A2HSOFTINT (VIDC_CPU_CS_BASE_OFFS + 0x18)
+#define VIDC_CPU_CS_A2HSOFTINTCLR (VIDC_CPU_CS_BASE_OFFS + 0x1C)
+#define VIDC_CPU_CS_SCIACMD (VIDC_CPU_CS_BASE_OFFS + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define VIDC_CPU_CS_SCIACMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x4C)
+#define VIDC_CPU_CS_SCIACMDARG0_BMSK 0xff
+#define VIDC_CPU_CS_SCIACMDARG0_SHFT 0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK 0xfe
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT 0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK 0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT 0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY 0x100
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK 0x40000000
+
+/* HFI_QTBL_INFO */
+#define VIDC_CPU_CS_SCIACMDARG1 (VIDC_CPU_CS_BASE_OFFS + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define VIDC_CPU_CS_SCIACMDARG2 (VIDC_CPU_CS_BASE_OFFS + 0x54)
+
+/* HFI_VERSION_INFO */
+#define VIDC_CPU_CS_SCIACMDARG3 (VIDC_CPU_CS_BASE_OFFS + 0x58)
+#define VIDC_CPU_IC_IRQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x00)
+#define VIDC_CPU_IC_FIQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x04)
+#define VIDC_CPU_IC_RAWINTR (VIDC_CPU_IC_BASE_OFFS + 0x08)
+#define VIDC_CPU_IC_INTSELECT (VIDC_CPU_IC_BASE_OFFS + 0x0C)
+#define VIDC_CPU_IC_INTENABLE (VIDC_CPU_IC_BASE_OFFS + 0x10)
+#define VIDC_CPU_IC_INTENACLEAR (VIDC_CPU_IC_BASE_OFFS + 0x14)
+#define VIDC_CPU_IC_SOFTINT (VIDC_CPU_IC_BASE_OFFS + 0x18)
+#define VIDC_CPU_IC_SOFTINT_H2A_BMSK 0x8000
+#define VIDC_CPU_IC_SOFTINT_H2A_SHFT 0xF
+#define VIDC_CPU_IC_SOFTINTCLEAR (VIDC_CPU_IC_BASE_OFFS + 0x1C)
+
+/*---------------------------------------------------------------------------
+ * MODULE: vidc_wrapper
+ *--------------------------------------------------------------------------*/
+#define VIDC_WRAPPER_BASE_OFFS 0x000E0000
+
+#define VIDC_WRAPPER_HW_VERSION (VIDC_WRAPPER_BASE_OFFS + 0x00)
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK 0x78000000
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK 0xFFF0000
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16
+#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK 0xFFFF
+
+#define VIDC_WRAPPER_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x04)
+
+#define VIDC_WRAPPER_INTR_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x0C)
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK 0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT 0x2
+
+#define VIDC_WRAPPER_INTR_MASK (VIDC_WRAPPER_BASE_OFFS + 0x10)
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT 0x3
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT 0x2
+
+#define VIDC_WRAPPER_INTR_CLEAR (VIDC_WRAPPER_BASE_OFFS + 0x14)
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK 0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT 0x2
+
+#define VIDC_WRAPPER_VBIF_XIN_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x18)
+#define VIDC_WRAPPER_VBIF_XIN_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x1C)
+#define VIDC_WRAPPER_CPU_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x2000)
+#define VIDC_WRAPPER_VBIF_XIN_CPU_SW_RESET \
+ (VIDC_WRAPPER_BASE_OFFS + 0x2004)
+#define VIDC_WRAPPER_AXI_HALT (VIDC_WRAPPER_BASE_OFFS + 0x2008)
+#define VIDC_WRAPPER_AXI_HALT_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x200C)
+#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010)
+#define VIDC_VENUS_VBIF_CLK_ON (VIDC_VBIF_BASE_OFFS + 0x4)
+#define VIDC_VBIF_IN_RD_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xB0)
+#define VIDC_VBIF_IN_RD_LIM_CONF1 (VIDC_VBIF_BASE_OFFS + 0xB4)
+#define VIDC_VBIF_IN_RD_LIM_CONF2 (VIDC_VBIF_BASE_OFFS + 0xB8)
+#define VIDC_VBIF_IN_RD_LIM_CONF3 (VIDC_VBIF_BASE_OFFS + 0xBC)
+#define VIDC_VBIF_IN_WR_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xC0)
+#define VIDC_VBIF_IN_WR_LIM_CONF1 (VIDC_VBIF_BASE_OFFS + 0xC4)
+#define VIDC_VBIF_IN_WR_LIM_CONF2 (VIDC_VBIF_BASE_OFFS + 0xC8)
+#define VIDC_VBIF_IN_WR_LIM_CONF3 (VIDC_VBIF_BASE_OFFS + 0xCC)
+#define VIDC_VBIF_OUT_RD_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xD0)
+#define VIDC_VBIF_OUT_WR_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xD4)
+#define VIDC_VBIF_DDR_OUT_MAX_BURST (VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VBIF_OCMEM_OUT_MAX_BURST (VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VBIF_DDR_ARB_CONF0 (VIDC_VBIF_BASE_OFFS + 0xF4)
+#define VIDC_VBIF_DDR_ARB_CONF1 (VIDC_VBIF_BASE_OFFS + 0xF8)
+#define VIDC_VBIF_ROUND_ROBIN_QOS_ARB (VIDC_VBIF_BASE_OFFS + 0x124)
+#define VIDC_VBIF_OUT_AXI_AOOO_EN (VIDC_VBIF_BASE_OFFS + 0x178)
+#define VIDC_VBIF_OUT_AXI_AOOO (VIDC_VBIF_BASE_OFFS + 0x17C)
+#define VIDC_VBIF_ARB_CTL (VIDC_VBIF_BASE_OFFS + 0xF0)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF0 (VIDC_VBIF_BASE_OFFS + 0x160)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF1 (VIDC_VBIF_BASE_OFFS + 0x164)
+#define VIDC_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0xC00)
+#define VIDC_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0xC04)
+#define VIDC_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0xC08)
+#define VIDC_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0xC10)
+#define VIDC_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0xC18)
+#define VENUS_VBIF_AXI_HALT_CTRL0 (VIDC_VBIF_BASE_OFFS + 0x208)
+#define VENUS_VBIF_AXI_HALT_CTRL1 (VIDC_VBIF_BASE_OFFS + 0x20C)
+
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
+
+#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
+ (VIDC_WRAPPER_BASE_OFFS + 0x20)
+#define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
+ (VIDC_WRAPPER_BASE_OFFS + 0x24)
+
+#define VIDC_CTRL_INIT 0x000D2048
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__M 0xFFFFFFFE
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__S 1
+#define VIDC_CTRL_INIT_CTRL__M 0x00000001
+#define VIDC_CTRL_INIT_CTRL__S 0
+
+#define VIDC_CTRL_STATUS 0x000D204C
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__M 0xFFFFFF00
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__S 8
+#define VIDC_CTRL_ERROR_STATUS__M 0x000000FE
+#define VIDC_CTRL_ERROR_STATUS__S 1
+#define VIDC_CTRL_INIT_STATUS__M 0x00000001
+#define VIDC_CTRL_INIT_STATUS__S 0
+
+#define VIDC_QTBL_INFO 0x000D2050
+#define VIDC_QTBL_HOSTID__M 0xFF000000
+#define VIDC_QTBL_HOSTID__S 24
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__M 0x00FFFF00
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__S 8
+#define VIDC_QTBL_STATUS__M 0x000000FF
+#define VIDC_QTBL_STATUS__S 0
+
+#define VIDC_QTBL_ADDR 0x000D2054
+
+#define VIDC_VERSION_INFO 0x000D2058
+#define VIDC_VERSION_INFO_MAJOR__M 0xF0000000
+#define VIDC_VERSION_INFO_MAJOR__S 28
+#define VIDC_VERSION_INFO_MINOR__M 0x0FFFFFE0
+#define VIDC_VERSION_INFO_MINOR__S 5
+#define VIDC_VERSION_INFO_BRANCH__M 0x0000001F
+#define VIDC_VERSION_INFO_BRANCH__S 0
+
+#define VIDC_SFR_ADDR 0x000D205C
+#define VIDC_MMAP_ADDR 0x000D2060
+#define VIDC_UC_REGION_ADDR 0x000D2064
+#define VIDC_UC_REGION_SIZE 0x000D2068
+
+#endif
diff --git a/drivers/media/platform/msm/vidc/vmem/Kconfig b/drivers/media/platform/msm/vidc/vmem/Kconfig
new file mode 100644
index 000000000000..e602e52da383
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/Kconfig
@@ -0,0 +1,3 @@
+menuconfig MSM_VIDC_VMEM
+ bool "Qualcomm Technologies Inc MSM VMEM driver"
+ depends on ARCH_QCOM && MSM_VIDC_V4L2
diff --git a/drivers/media/platform/msm/vidc/vmem/Makefile b/drivers/media/platform/msm/vidc/vmem/Makefile
new file mode 100644
index 000000000000..713b92e64544
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MSM_VIDC_VMEM) := vmem.o \
+ vmem_debugfs.o
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.c b/drivers/media/platform/msm/vidc/vmem/vmem.c
new file mode 100644
index 000000000000..0035457d5cba
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/vmem.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2014-2015, 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msm-bus.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "vmem.h"
+#include "vmem_debugfs.h"
+
+/* Registers */
+#define OCIMEM_BASE(v) ((uint8_t *)(v)->reg.base)
+#define OCIMEM_HW_VERSION(v) (OCIMEM_BASE(v) + 0x00)
+#define OCIMEM_HW_PROFILE(v) (OCIMEM_BASE(v) + 0x04)
+#define OCIMEM_GEN_CTL(v) (OCIMEM_BASE(v) + 0x08)
+#define OCIMEM_GEN_STAT(v) (OCIMEM_BASE(v) + 0x0C)
+#define OCIMEM_INTC_CLR(v) (OCIMEM_BASE(v) + 0x10)
+#define OCIMEM_INTC_MASK(v) (OCIMEM_BASE(v) + 0x14)
+#define OCIMEM_INTC_STAT(v) (OCIMEM_BASE(v) + 0x18)
+#define OCIMEM_OSW_STATUS(v) (OCIMEM_BASE(v) + 0x1C)
+#define OCIMEM_PSCGC_TIMERS(v) (OCIMEM_BASE(v) + 0x34)
+#define OCIMEM_PSCGC_STAT(v) (OCIMEM_BASE(v) + 0x38)
+#define OCIMEM_PSCGC_M0_M7_CTL(v) (OCIMEM_BASE(v) + 0x3C)
+#define OCIMEM_ERR_ADDRESS(v) (OCIMEM_BASE(v) + 0x60)
+#define OCIMEM_AXI_ERR_SYNDROME(v) (OCIMEM_BASE(v) + 0x64)
+#define OCIMEM_DEBUG_CTL(v) (OCIMEM_BASE(v) + 0x68)
+
+/*
+ * Helper macro to help out with masks and shifts for values packed into
+ * registers.
+ */
+#define DECLARE_TYPE(__type, __end, __start) \
+ static const unsigned int __type##_BITS = (__end) - (__start) + 1; \
+ static const unsigned int __type##_SHIFT = (__start); \
+ static const unsigned int __type##_MASK = GENMASK((__end), (__start)); \
+ static inline unsigned int __type(uint32_t val) \
+ { \
+ return (val & __type##_MASK) >> __type##_SHIFT; \
+ } \
+ static inline uint32_t __type##_UPDATE(unsigned int val) \
+ { \
+ return (val << __type##_SHIFT) & __type##_MASK; \
+ }
+
+/* Register masks */
+/* OCIMEM_PSCGC_M0_M7_CTL */
+DECLARE_TYPE(BANK0_STATE, 3, 0)
+DECLARE_TYPE(BANK1_STATE, 7, 4)
+DECLARE_TYPE(BANK2_STATE, 11, 8)
+DECLARE_TYPE(BANK3_STATE, 15, 12)
+/* OCIMEM_PSCGC_TIMERS */
+DECLARE_TYPE(TIMERS_WAKEUP, 3, 0)
+DECLARE_TYPE(TIMERS_SLEEP, 11, 8)
+/* OCIMEM_HW_VERSION */
+DECLARE_TYPE(VERSION_STEP, 15, 0)
+DECLARE_TYPE(VERSION_MINOR, 27, 16)
+DECLARE_TYPE(VERSION_MAJOR, 31, 28)
+/* OCIMEM_HW_PROFILE */
+DECLARE_TYPE(PROFILE_BANKS, 16, 12)
+/* OCIMEM_AXI_ERR_SYNDROME */
+DECLARE_TYPE(ERR_SYN_ATID, 14, 8);
+DECLARE_TYPE(ERR_SYN_AMID, 23, 16);
+DECLARE_TYPE(ERR_SYN_APID, 28, 24);
+DECLARE_TYPE(ERR_SYN_ABID, 31, 29);
+/* OCIMEM_INTC_MASK */
+DECLARE_TYPE(AXI_ERR_INT, 0, 0);
+
+/* Internal stuff */
+#define MAX_BANKS 4
+#define BYTES_PER_BANK SZ_256K
+
+enum bank_state {
+ BANK_STATE_NORM_PASSTHRU = 0b000,
+ BANK_STATE_NORM_FORCE_CORE_ON = 0b010,
+ BANK_STATE_NORM_FORCE_PERIPH_ON = 0b001,
+ BANK_STATE_NORM_FORCE_ALL_ON = 0b011,
+ BANK_STATE_SLEEP_RET = 0b110,
+ BANK_STATE_SLEEP_RET_PERIPH_ON = 0b111,
+ BANK_STATE_SLEEP_NO_RET = 0b100,
+};
+
+struct vmem {
+ int irq;
+ int num_banks;
+ struct {
+ struct resource *resource;
+ void __iomem *base;
+ } reg, mem;
+ struct regulator *vdd;
+ struct {
+ const char *name;
+ struct clk *clk;
+ } *clocks;
+ int num_clocks;
+ struct {
+ struct msm_bus_scale_pdata *pdata;
+ uint32_t priv;
+ } bus;
+ atomic_t alloc_count;
+ struct dentry *debugfs_root;
+};
+
+static struct vmem *vmem;
+
+static inline u32 __readl(void * __iomem addr)
+{
+ u32 value = 0;
+
+ pr_debug("read %p ", addr);
+ value = readl_relaxed(addr);
+ pr_debug("-> %08x\n", value);
+
+ return value;
+}
+
+static inline void __writel(u32 val, void * __iomem addr)
+{
+ pr_debug("write %08x -> %p\n", val, addr);
+ writel_relaxed(val, addr);
+ /*
+ * Commit all writes via a mem barrier, as subsequent __readl()
+ * will depend on the state that's set via __writel().
+ */
+ mb();
+}
+
+static inline void __wait_timer(struct vmem *v, bool wakeup)
+{
+ uint32_t ticks = 0;
+ unsigned int (*timer)(uint32_t) = wakeup ?
+ TIMERS_WAKEUP : TIMERS_SLEEP;
+
+ ticks = timer(__readl(OCIMEM_PSCGC_TIMERS(v)));
+
+ /* Sleep for `ticks` nanoseconds as per h/w spec */
+ ndelay(ticks);
+}
+
+static inline void __wait_wakeup(struct vmem *v)
+{
+ return __wait_timer(v, true);
+}
+
+static inline void __wait_sleep(struct vmem *v)
+{
+ return __wait_timer(v, false);
+}
+
+static inline int __power_on(struct vmem *v)
+{
+ int rc = 0, c = 0;
+
+ rc = msm_bus_scale_client_update_request(v->bus.priv, 1);
+ if (rc) {
+ pr_err("Failed to vote for buses (%d)\n", rc);
+ goto exit;
+ }
+ pr_debug("Voted for buses\n");
+
+ rc = regulator_enable(v->vdd);
+ if (rc) {
+ pr_err("Failed to power on gdsc (%d)", rc);
+ goto unvote_bus;
+ }
+ pr_debug("Enabled regulator vdd\n");
+
+ for (c = 0; c < v->num_clocks; ++c) {
+ rc = clk_prepare_enable(v->clocks[c].clk);
+ if (rc) {
+ pr_err("Failed to enable %s clock (%d)\n",
+ v->clocks[c].name, rc);
+ goto disable_clocks;
+ }
+
+ pr_debug("Enabled clock %s\n", v->clocks[c].name);
+ }
+
+ return 0;
+disable_clocks:
+ for (--c; c >= 0; c--)
+ clk_disable_unprepare(v->clocks[c].clk);
+ regulator_disable(v->vdd);
+unvote_bus:
+ msm_bus_scale_client_update_request(v->bus.priv, 0);
+exit:
+ return rc;
+}
+
+static inline int __power_off(struct vmem *v)
+{
+ int c = 0;
+
+ for (c = 0; c < v->num_clocks; ++c) {
+ clk_disable_unprepare(v->clocks[c].clk);
+ pr_debug("Disabled clock %s\n", v->clocks[c].name);
+ }
+
+ regulator_disable(v->vdd);
+ pr_debug("Disabled regulator vdd\n");
+
+ msm_bus_scale_client_update_request(v->bus.priv, 0);
+ pr_debug("Unvoted for buses\n");
+
+ return 0;
+}
+
+static inline enum bank_state __bank_get_state(struct vmem *v,
+ unsigned int bank)
+{
+ unsigned int (*func[MAX_BANKS])(uint32_t) = {
+ BANK0_STATE, BANK1_STATE, BANK2_STATE, BANK3_STATE
+ };
+
+ BUG_ON(bank >= ARRAY_SIZE(func));
+ return func[bank](__readl(OCIMEM_PSCGC_M0_M7_CTL(v)));
+}
+
+static inline void __bank_set_state(struct vmem *v, unsigned int bank,
+ enum bank_state state)
+{
+ uint32_t bank_state = 0;
+ struct {
+ uint32_t (*update)(unsigned int);
+ uint32_t mask;
+ } banks[MAX_BANKS] = {
+ {BANK0_STATE_UPDATE, BANK0_STATE_MASK},
+ {BANK1_STATE_UPDATE, BANK1_STATE_MASK},
+ {BANK2_STATE_UPDATE, BANK2_STATE_MASK},
+ {BANK3_STATE_UPDATE, BANK3_STATE_MASK},
+ };
+
+ BUG_ON(bank >= ARRAY_SIZE(banks));
+
+ bank_state = __readl(OCIMEM_PSCGC_M0_M7_CTL(v));
+ bank_state &= ~banks[bank].mask;
+ bank_state |= banks[bank].update(state);
+
+ __writel(bank_state, OCIMEM_PSCGC_M0_M7_CTL(v));
+}
+
+static inline void __toggle_interrupts(struct vmem *v, bool enable)
+{
+ uint32_t ints = __readl(OCIMEM_INTC_MASK(v)),
+ mask = AXI_ERR_INT_MASK,
+ update = AXI_ERR_INT_UPDATE(!enable);
+
+ ints &= ~mask;
+ ints |= update;
+
+ __writel(ints, OCIMEM_INTC_MASK(v));
+}
+
+static void __enable_interrupts(struct vmem *v)
+{
+ pr_debug("Enabling interrupts\n");
+ enable_irq(v->irq);
+ __toggle_interrupts(v, true);
+}
+
+static void __disable_interrupts(struct vmem *v)
+{
+ pr_debug("Disabling interrupts\n");
+ __toggle_interrupts(v, false);
+ disable_irq_nosync(v->irq);
+}
+
+/**
+ * vmem_allocate: - Allocates memory from VMEM. Allocations have a few
+ * restrictions: only allocations of the entire VMEM memory are allowed, and
+ * , as a result, only single outstanding allocations are allowed.
+ *
+ * @size: amount of bytes to allocate
+ * @addr: A pointer to phys_addr_t where the physical address of the memory
+ * allocated is stored.
+ *
+ * Return: 0 in case of successful allocation (i.e. *addr != NULL). -ENOTSUPP,
+ * if platform doesn't support VMEM. -EEXIST, if there are outstanding VMEM
+ * allocations. -ENOMEM, if platform can't support allocation of `size` bytes.
+ * -EAGAIN, if `size` does not allocate the entire VMEM region. -EIO in case of
+ * internal errors.
+ */
+int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+ int rc = 0, c = 0;
+ resource_size_t max_size = 0;
+
+ if (!vmem) {
+ pr_err("No vmem, try rebooting your device\n");
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ max_size = resource_size(vmem->mem.resource);
+
+ if (atomic_read(&vmem->alloc_count)) {
+ pr_err("Only single allocations allowed for vmem\n");
+ rc = -EEXIST;
+ goto exit;
+ } else if (size > max_size) {
+ pr_err("Out of memory, have max %pa\n", &max_size);
+ rc = -ENOMEM;
+ goto exit;
+ } else if (size != max_size) {
+ pr_err("Only support allocations of size %pa\n", &max_size);
+ rc = -EAGAIN;
+ goto exit;
+ }
+
+ rc = __power_on(vmem);
+ if (rc) {
+ pr_err("Failed power on (%d)\n", rc);
+ goto exit;
+ }
+
+ BUG_ON(vmem->num_banks != DIV_ROUND_UP(size, BYTES_PER_BANK));
+
+ /* Make sure all the banks are sleeping (default) */
+ for (c = 0; c < vmem->num_banks; ++c) {
+ enum bank_state curr_bank_state = __bank_get_state(vmem, c);
+
+ if (curr_bank_state != BANK_STATE_SLEEP_NO_RET) {
+ pr_err("Found bank %d in a wrong state, expected %d, was %d\n",
+ c, BANK_STATE_SLEEP_NO_RET,
+ curr_bank_state);
+ rc = -EIO;
+ goto disable_clocks;
+ }
+ }
+
+ /* Turn on the necessary banks */
+ for (c = 0; c < vmem->num_banks; ++c) {
+ __bank_set_state(vmem, c, BANK_STATE_NORM_FORCE_CORE_ON);
+ __wait_wakeup(vmem);
+ }
+
+ /* Enable interrupts to detect faults */
+ __enable_interrupts(vmem);
+
+ atomic_inc(&vmem->alloc_count);
+ *addr = (phys_addr_t)vmem->mem.resource->start;
+ return 0;
+
+disable_clocks:
+ __power_off(vmem);
+exit:
+ return rc;
+}
+
+/**
+ * vmem_free: - Frees the memory allocated via vmem_allocate. Undefined
+ * behaviour if to_free is a not a pointer returned via vmem_allocate
+ */
+void vmem_free(phys_addr_t to_free)
+{
+ int c = 0;
+ if (!to_free || !vmem)
+ return;
+
+ BUG_ON(atomic_read(&vmem->alloc_count) == 0);
+
+ for (c = 0; c < vmem->num_banks; ++c) {
+ enum bank_state curr_state = __bank_get_state(vmem, c);
+
+ if (curr_state != BANK_STATE_NORM_FORCE_CORE_ON) {
+ pr_warn("When freeing, expected bank state to be %d, was instead %d\n",
+ BANK_STATE_NORM_FORCE_CORE_ON,
+ curr_state);
+ }
+
+ __bank_set_state(vmem, c, BANK_STATE_SLEEP_NO_RET);
+ }
+
+ __disable_interrupts(vmem);
+ __power_off(vmem);
+ atomic_dec(&vmem->alloc_count);
+}
+
+struct vmem_interrupt_cookie {
+ struct vmem *vmem;
+ struct work_struct work;
+};
+
+static void __irq_helper(struct work_struct *work)
+{
+ struct vmem_interrupt_cookie *cookie = container_of(work,
+ struct vmem_interrupt_cookie, work);
+ struct vmem *v = cookie->vmem;
+ unsigned int stat, gen_stat, pscgc_stat, err_addr_abs,
+ err_addr_rel, err_syn;
+
+ stat = __readl(OCIMEM_INTC_STAT(v));
+ gen_stat = __readl(OCIMEM_GEN_CTL(v));
+ pscgc_stat = __readl(OCIMEM_PSCGC_STAT(v));
+
+ err_addr_abs = __readl(OCIMEM_ERR_ADDRESS(v));
+ err_addr_rel = v->mem.resource->start - err_addr_abs;
+
+ err_syn = __readl(OCIMEM_AXI_ERR_SYNDROME(v));
+
+ pr_crit("Detected a fault on VMEM:\n");
+ pr_cont("\tinterrupt status: %x\n", stat);
+ pr_cont("\tgeneral status: %x\n", gen_stat);
+ pr_cont("\tmemory status: %x\n", pscgc_stat);
+ pr_cont("\tfault address: %x (absolute), %x (relative)\n",
+ err_addr_abs, err_addr_rel);
+ pr_cont("\tfault bank: %x\n", err_addr_rel / BYTES_PER_BANK);
+ pr_cont("\tfault core: %u (mid), %u (pid), %u (bid)\n",
+ ERR_SYN_AMID(err_syn), ERR_SYN_APID(err_syn),
+ ERR_SYN_ABID(err_syn));
+
+ /* Clear the interrupt */
+ __writel(0, OCIMEM_INTC_CLR(v));
+
+ __enable_interrupts(v);
+}
+
+static struct vmem_interrupt_cookie interrupt_cookie;
+
+static irqreturn_t __irq_handler(int irq, void *cookie)
+{
+ struct vmem *v = cookie;
+ irqreturn_t status = __readl(OCIMEM_INTC_STAT(vmem)) ?
+ IRQ_HANDLED : IRQ_NONE;
+
+ if (status != IRQ_NONE) {
+ /* Mask further interrupts while handling this one */
+ __disable_interrupts(v);
+
+ interrupt_cookie.vmem = v;
+ INIT_WORK(&interrupt_cookie.work, __irq_helper);
+ schedule_work(&interrupt_cookie.work);
+ }
+
+ return status;
+}
+
+static inline int __init_resources(struct vmem *v,
+ struct platform_device *pdev)
+{
+ int rc = 0, c = 0;
+
+ v->irq = platform_get_irq(pdev, 0);
+ if (v->irq < 0) {
+ rc = v->irq;
+ pr_err("Failed to get irq (%d)\n", rc);
+ v->irq = 0;
+ goto exit;
+ }
+
+ /* Registers and memory */
+ v->reg.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "reg-base");
+ if (!v->reg.resource) {
+ pr_err("Failed to find register base\n");
+ rc = -ENOENT;
+ goto exit;
+ }
+
+ v->reg.base = devm_ioremap_resource(&pdev->dev, v->reg.resource);
+ if (IS_ERR_OR_NULL(v->reg.base)) {
+ rc = PTR_ERR(v->reg.base) ?: -EIO;
+ pr_err("Failed to map register base into kernel (%d)\n", rc);
+ v->reg.base = NULL;
+ goto exit;
+ }
+
+ pr_debug("Register range: %pa -> %pa\n", &v->reg.resource->start,
+ &v->reg.resource->end);
+
+ v->mem.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "mem-base");
+ if (!v->mem.resource) {
+ pr_err("Failed to find memory base\n");
+ rc = -ENOENT;
+ goto exit;
+ }
+
+ v->mem.base = NULL;
+ pr_debug("Memory range: %pa -> %pa\n", &v->mem.resource->start,
+ &v->mem.resource->end);
+
+ /* Buses, Clocks & Regulators*/
+ v->num_clocks = of_property_count_strings(pdev->dev.of_node,
+ "clock-names");
+ if (v->num_clocks <= 0) {
+ pr_err("Can't find any clocks\n");
+ goto exit;
+ }
+
+ v->clocks = devm_kzalloc(&pdev->dev, sizeof(*v->clocks) * v->num_clocks,
+ GFP_KERNEL);
+ if (!v->clocks) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ for (c = 0; c < v->num_clocks; ++c) {
+ const char *name = NULL;
+ struct clk *temp = NULL;
+
+ of_property_read_string(pdev->dev.of_node, "clock-names",
+ &name);
+ temp = devm_clk_get(&pdev->dev, name);
+ if (IS_ERR_OR_NULL(temp)) {
+ rc = PTR_ERR(temp) ?: -ENOENT;
+ pr_err("Failed to find %s (%d)\n", name, rc);
+ goto exit;
+ }
+
+ v->clocks[c].clk = temp;
+ v->clocks[c].name = name;
+ }
+
+ v->vdd = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR_OR_NULL(v->vdd)) {
+ rc = PTR_ERR(v->vdd) ?: -ENOENT;
+ pr_err("Failed to find regulator (vdd) (%d)\n", rc);
+ goto exit;
+ }
+
+ v->bus.pdata = msm_bus_cl_get_pdata(pdev);
+ if (IS_ERR_OR_NULL(v->bus.pdata)) {
+ rc = PTR_ERR(v->bus.pdata) ?: -ENOENT;
+ pr_err("Failed to find bus vectors (%d)\n", rc);
+ goto exit;
+ }
+
+ v->bus.priv = msm_bus_scale_register_client(v->bus.pdata);
+ if (!v->bus.priv) {
+ rc = -EBADHANDLE;
+ pr_err("Failed to register bus client\n");
+ goto free_pdata;
+ }
+
+ /* Misc. */
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,banks",
+ &v->num_banks);
+ if (rc || !v->num_banks) {
+ pr_err("Failed reading (or found invalid) qcom,banks in %s (%d)\n",
+ of_node_full_name(pdev->dev.of_node), rc);
+ rc = -ENOENT;
+ goto free_pdata;
+ }
+
+ pr_debug("Found configuration with %d banks\n", v->num_banks);
+
+ return 0;
+free_pdata:
+ msm_bus_cl_clear_pdata(v->bus.pdata);
+exit:
+ return rc;
+}
+
+static inline void __uninit_resources(struct vmem *v,
+ struct platform_device *pdev)
+{
+ int c = 0;
+
+ msm_bus_cl_clear_pdata(v->bus.pdata);
+ v->bus.pdata = NULL;
+ v->bus.priv = 0;
+
+ for (c = 0; c < v->num_clocks; ++c) {
+ v->clocks[c].clk = NULL;
+ v->clocks[c].name = NULL;
+ }
+
+ v->vdd = NULL;
+}
+
+static int vmem_probe(struct platform_device *pdev)
+{
+ uint32_t version = 0, num_banks = 0, rc = 0;
+ struct vmem *v = NULL;
+
+ if (vmem) {
+ pr_err("Only one instance of %s allowed", pdev->name);
+ return -EEXIST;
+ }
+
+ v = devm_kzalloc(&pdev->dev, sizeof(*v), GFP_KERNEL);
+ if (!v) {
+ pr_err("Failed allocate context memory in probe\n");
+ return -ENOMEM;
+ }
+
+
+ rc = __init_resources(v, pdev);
+ if (rc) {
+ pr_err("Failed to read resources\n");
+ goto exit;
+ }
+
+ /*
+ * For now, only support up to 4 banks. It's unrealistic that VMEM has
+ * more banks than that (even in the future).
+ */
+ if (v->num_banks > MAX_BANKS) {
+ pr_err("Number of banks (%d) exceeds what's supported (%d)\n",
+ v->num_banks, MAX_BANKS);
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ /* Cross check the platform resources with what's available on chip */
+ rc = __power_on(v);
+ if (rc) {
+ pr_err("Failed to power on (%d)\n", rc);
+ goto exit;
+ }
+
+ version = __readl(OCIMEM_HW_VERSION(v));
+ pr_debug("v%d.%d.%d\n", VERSION_MAJOR(version), VERSION_MINOR(version),
+ VERSION_STEP(version));
+
+ num_banks = PROFILE_BANKS(__readl(OCIMEM_HW_PROFILE(v)));
+ pr_debug("Found %d banks on chip\n", num_banks);
+ if (v->num_banks > num_banks) {
+ pr_err("Platform configuration of %d banks exceeds what's available on chip (%d)\n",
+ v->num_banks, num_banks);
+ rc = -EINVAL;
+ goto disable_clocks;
+ }
+
+ if (v->num_banks * BYTES_PER_BANK >
+ resource_size(v->mem.resource)) {
+ pr_err("Too many banks in configuration\n");
+ rc = -E2BIG;
+ goto disable_clocks;
+ }
+
+ rc = devm_request_irq(&pdev->dev, v->irq, __irq_handler,
+ IRQF_TRIGGER_HIGH, "vmem", v);
+ if (rc) {
+ pr_err("Failed to setup irq (%d)\n", rc);
+ goto disable_clocks;
+ }
+
+ __disable_interrupts(v);
+
+ /* Everything good so far, set up the global context and debug hooks */
+ pr_info("Up and running with %d banks of memory from %pR\n",
+ v->num_banks, &v->mem.resource);
+ v->debugfs_root = vmem_debugfs_init(pdev);
+ platform_set_drvdata(pdev, v);
+ vmem = v;
+
+disable_clocks:
+ __power_off(v);
+exit:
+ return rc;
+}
+
+static int vmem_remove(struct platform_device *pdev)
+{
+ struct vmem *v = platform_get_drvdata(pdev);
+
+ BUG_ON(v != vmem);
+
+ __uninit_resources(v, pdev);
+ vmem_debugfs_deinit(v->debugfs_root);
+ vmem = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id vmem_of_match[] = {
+ {.compatible = "qcom,msm-vmem"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, vmem_of_match);
+
+static struct platform_driver vmem_driver = {
+ .probe = vmem_probe,
+ .remove = vmem_remove,
+ .driver = {
+ .name = "msm_vidc_vmem",
+ .owner = THIS_MODULE,
+ .of_match_table = vmem_of_match,
+ },
+};
+
+static int __init vmem_init(void)
+{
+ return platform_driver_register(&vmem_driver);
+}
+
+static void __exit vmem_exit(void)
+{
+ platform_driver_unregister(&vmem_driver);
+}
+
+module_init(vmem_init);
+module_exit(vmem_exit);
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.h b/drivers/media/platform/msm/vidc/vmem/vmem.h
new file mode 100644
index 000000000000..751904e00755
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/vmem.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __VMEM_H__
+#define __VMEM_H__
+
+#ifdef CONFIG_MSM_VIDC_VMEM
+
+int vmem_allocate(size_t size, phys_addr_t *addr);
+void vmem_free(phys_addr_t to_free);
+
+#else
+
+static inline int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+ return -ENODEV;
+}
+
+static inline void vmem_free(phys_addr_t to_free)
+{
+}
+
+#endif
+
+#endif /* __VMEM_H__ */
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.c b/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.c
new file mode 100644
index 000000000000..7b9b230bedba
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 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/debugfs.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include "vmem.h"
+
+struct vmem_debugfs_cookie {
+ phys_addr_t addr;
+ size_t size;
+};
+
+static int __vmem_alloc_get(void *priv, u64 *val)
+{
+ struct vmem_debugfs_cookie *cookie = priv;
+
+ *val = cookie->size;
+ return 0;
+}
+
+static int __vmem_alloc_set(void *priv, u64 val)
+{
+ struct vmem_debugfs_cookie *cookie = priv;
+ int rc = 0;
+
+ switch (val) {
+ case 0: /* free */
+ vmem_free(cookie->addr);
+ cookie->size = 0;
+ break;
+ default:
+ rc = vmem_allocate(val, &cookie->addr);
+ cookie->size = val;
+ break;
+ }
+
+ return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_vmem_alloc, __vmem_alloc_get,
+ __vmem_alloc_set, "%llu");
+
+struct dentry *vmem_debugfs_init(struct platform_device *pdev)
+{
+ struct vmem_debugfs_cookie *alloc_cookie = NULL;
+ struct dentry *debugfs_root = NULL;
+
+ alloc_cookie = devm_kzalloc(&pdev->dev, sizeof(*alloc_cookie),
+ GFP_KERNEL);
+ if (!alloc_cookie)
+ goto exit;
+
+ debugfs_root = debugfs_create_dir("vmem", NULL);
+ if (IS_ERR_OR_NULL(debugfs_root)) {
+ pr_warn("Failed to create '<debugfs>/vmem'\n");
+ debugfs_root = NULL;
+ goto exit;
+ }
+
+ debugfs_create_file("alloc", S_IRUSR | S_IWUSR, debugfs_root,
+ alloc_cookie, &fops_vmem_alloc);
+
+exit:
+ return debugfs_root;
+}
+
+void vmem_debugfs_deinit(struct dentry *debugfs_root)
+{
+ debugfs_remove_recursive(debugfs_root);
+}
+
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.h b/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.h
new file mode 100644
index 000000000000..6d86ffbd8401
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/vmem/vmem_debugfs.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+#ifndef __VMEM_DEBUGFS_H__
+#define __VMEM_DEBUGFS_H__
+
+#include <linux/debugfs.h>
+
+struct dentry *vmem_debugfs_init(struct platform_device *pdev);
+void vmem_debugfs_deinit(struct dentry *debugfs_root);
+
+#endif /* __VMEM_DEBUGFS_H__ */
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index cc16e76a2493..7451bc63497e 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -913,7 +913,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
/*
* Make sure the requested values and current defaults are sane.
*/
- num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
+ num_buffers = min_t(unsigned int, req->count, VB2_MAX_FRAME);
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
@@ -1018,7 +1018,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
unsigned int num_planes = 0, num_buffers, allocated_buffers;
int ret;
- if (q->num_buffers == VIDEO_MAX_FRAME) {
+ if (q->num_buffers == VB2_MAX_FRAME) {
dprintk(1, "maximum number of buffers already allocated\n");
return -ENOBUFS;
}
@@ -1030,7 +1030,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type);
}
- num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers);
+ num_buffers = min(create->count, VB2_MAX_FRAME - q->num_buffers);
/*
* Ask the driver, whether the requested number of buffers, planes per
@@ -2755,7 +2755,7 @@ struct vb2_fileio_data {
struct v4l2_requestbuffers req;
struct v4l2_plane p;
struct v4l2_buffer b;
- struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
+ struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
unsigned int cur_index;
unsigned int initial_index;
unsigned int q_count;
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 4c29e72c4177..c36c90309d42 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -45,4 +45,8 @@ extern int qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
extern int qcom_scm_get_feat_version(u32 feat);
extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+extern int qcom_scm_set_video_state(u32 state, u32 spare);
+extern int qcom_scm_mem_protect_video_var(u32 start, u32 size,
+ u32 nonpixel_start,
+ u32 nonpixel_size);
#endif
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
new file mode 100644
index 000000000000..83aa7ee1c139
--- /dev/null
+++ b/include/media/msm_media_info.h
@@ -0,0 +1,611 @@
+#ifndef __MEDIA_INFO_H__
+#define __MEDIA_INFO_H__
+
+#ifndef MSM_MEDIA_ALIGN
+#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1)))
+#endif
+
+#ifndef MSM_MEDIA_ROUNDUP
+#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r))
+#endif
+
+enum color_fmts {
+ /* Venus NV12:
+ * YUV 4:2:0 image with a plane of 8 bit Y samples followed
+ * by an interleaved U/V plane containing 8 bit 2x2 subsampled
+ * colour difference samples.
+ *
+ * <-------- Y/UV_Stride -------->
+ * <------- Width ------->
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * U V U V U V U V U V U V . . . . ^
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . |
+ * U V U V U V U V U V U V . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . --> Buffer size alignment
+ *
+ * Y_Stride : Width aligned to 128
+ * UV_Stride : Width aligned to 128
+ * Y_Scanlines: Height aligned to 32
+ * UV_Scanlines: Height/2 aligned to 16
+ * Extradata: Arbitrary (software-imposed) padding
+ * Total size = align((Y_Stride * Y_Scanlines
+ * + UV_Stride * UV_Scanlines + Extradata), 4096)
+ */
+ COLOR_FMT_NV12,
+
+ /* Venus NV21:
+ * YUV 4:2:0 image with a plane of 8 bit Y samples followed
+ * by an interleaved V/U plane containing 8 bit 2x2 subsampled
+ * colour difference samples.
+ *
+ * <-------- Y/UV_Stride -------->
+ * <------- Width ------->
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * V U V U V U V U V U V U . . . . ^
+ * V U V U V U V U V U V U . . . . |
+ * V U V U V U V U V U V U . . . . |
+ * V U V U V U V U V U V U . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment
+ *
+ * Y_Stride : Width aligned to 128
+ * UV_Stride : Width aligned to 128
+ * Y_Scanlines: Height aligned to 32
+ * UV_Scanlines: Height/2 aligned to 16
+ * Extradata: Arbitrary (software-imposed) padding
+ * Total size = align((Y_Stride * Y_Scanlines
+ * + UV_Stride * UV_Scanlines + Extradata), 4096)
+ */
+ COLOR_FMT_NV21,
+ /* Venus NV12_MVTB:
+ * Two YUV 4:2:0 images/views one after the other
+ * in a top-bottom layout, same as NV12
+ * with a plane of 8 bit Y samples followed
+ * by an interleaved U/V plane containing 8 bit 2x2 subsampled
+ * colour difference samples.
+ *
+ *
+ * <-------- Y/UV_Stride -------->
+ * <------- Width ------->
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | |
+ * . . . . . . . . . . . . . . . . | View_1
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . V |
+ * U V U V U V U V U V U V . . . . ^ |
+ * U V U V U V U V U V U V . . . . | |
+ * U V U V U V U V U V U V . . . . | |
+ * U V U V U V U V U V U V . . . . UV_Scanlines |
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . V V
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | |
+ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | |
+ * . . . . . . . . . . . . . . . . | View_2
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . V |
+ * U V U V U V U V U V U V . . . . ^ |
+ * U V U V U V U V U V U V . . . . | |
+ * U V U V U V U V U V U V . . . . | |
+ * U V U V U V U V U V U V . . . . UV_Scanlines |
+ * . . . . . . . . . . . . . . . . | |
+ * . . . . . . . . . . . . . . . . V V
+ * . . . . . . . . . . . . . . . . --> Buffer size alignment
+ *
+ * Y_Stride : Width aligned to 128
+ * UV_Stride : Width aligned to 128
+ * Y_Scanlines: Height aligned to 32
+ * UV_Scanlines: Height/2 aligned to 16
+ * View_1 begin at: 0 (zero)
+ * View_2 begin at: Y_Stride * Y_Scanlines + UV_Stride * UV_Scanlines
+ * Extradata: Arbitrary (software-imposed) padding
+ * Total size = align((2*(Y_Stride * Y_Scanlines)
+ * + 2*(UV_Stride * UV_Scanlines) + Extradata), 4096)
+ */
+ COLOR_FMT_NV12_MVTB,
+ /* Venus NV12 UBWC:
+ * Compressed Macro-tile format for NV12.
+ * Contains 4 planes in the following order -
+ * (A) Y_Meta_Plane
+ * (B) Y_UBWC_Plane
+ * (C) UV_Meta_Plane
+ * (D) UV_UBWC_Plane
+ *
+ * Y_Meta_Plane consists of meta information to decode compressed
+ * tile data in Y_UBWC_Plane.
+ * Y_UBWC_Plane consists of Y data in compressed macro-tile format.
+ * UBWC decoder block will use the Y_Meta_Plane data together with
+ * Y_UBWC_Plane data to produce loss-less uncompressed 8 bit Y samples.
+ *
+ * UV_Meta_Plane consists of meta information to decode compressed
+ * tile data in UV_UBWC_Plane.
+ * UV_UBWC_Plane consists of UV data in compressed macro-tile format.
+ * UBWC decoder block will use UV_Meta_Plane data together with
+ * UV_UBWC_Plane data to produce loss-less uncompressed 8 bit 2x2
+ * subsampled color difference samples.
+ *
+ * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable
+ * and randomly accessible. There is no dependency between tiles.
+ *
+ * <----- Y_Meta_Stride ---->
+ * <-------- Width ------>
+ * M M M M M M M M M M M M . . ^ ^
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . Height |
+ * M M M M M M M M M M M M . . | Meta_Y_Scanlines
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . V |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . V
+ * <--Compressed tile Y Stride--->
+ * <------- Width ------->
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . . . V
+ * <----- UV_Meta_Stride ---->
+ * M M M M M M M M M M M M . . ^
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . M_UV_Scanlines
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * <--Compressed tile UV Stride--->
+ * U* V* U* V* U* V* U* V* . . . . ^
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ *
+ * Y_Stride = align(Width, 128)
+ * UV_Stride = align(Width, 128)
+ * Y_Scanlines = align(Height, 32)
+ * UV_Scanlines = align(Height/2, 16)
+ * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096)
+ * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096)
+ * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64)
+ * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16)
+ * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096)
+ * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64)
+ * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16)
+ * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096)
+ * Extradata = 8k
+ *
+ * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size +
+ * Y_Meta_Plane_size + UV_Meta_Plane_size + Extradata, 4096)
+ */
+ COLOR_FMT_NV12_UBWC,
+ /* Venus NV12 10-bit UBWC:
+ * Compressed Macro-tile format for NV12.
+ * Contains 4 planes in the following order -
+ * (A) Y_Meta_Plane
+ * (B) Y_UBWC_Plane
+ * (C) UV_Meta_Plane
+ * (D) UV_UBWC_Plane
+ *
+ * Y_Meta_Plane consists of meta information to decode compressed
+ * tile data in Y_UBWC_Plane.
+ * Y_UBWC_Plane consists of Y data in compressed macro-tile format.
+ * UBWC decoder block will use the Y_Meta_Plane data together with
+ * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples.
+ *
+ * UV_Meta_Plane consists of meta information to decode compressed
+ * tile data in UV_UBWC_Plane.
+ * UV_UBWC_Plane consists of UV data in compressed macro-tile format.
+ * UBWC decoder block will use UV_Meta_Plane data together with
+ * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2
+ * subsampled color difference samples.
+ *
+ * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable
+ * and randomly accessible. There is no dependency between tiles.
+ *
+ * <----- Y_Meta_Stride ----->
+ * <-------- Width ------>
+ * M M M M M M M M M M M M . . ^ ^
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . Height |
+ * M M M M M M M M M M M M . . | Meta_Y_Scanlines
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . V |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . V
+ * <--Compressed tile Y Stride--->
+ * <------- Width ------->
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . . . V
+ * <----- UV_Meta_Stride ---->
+ * M M M M M M M M M M M M . . ^
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . M_UV_Scanlines
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * <--Compressed tile UV Stride--->
+ * U* V* U* V* U* V* U* V* . . . . ^
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ *
+ *
+ * Y_Stride = align(Width * 4/3, 128)
+ * UV_Stride = align(Width * 4/3, 128)
+ * Y_Scanlines = align(Height, 32)
+ * UV_Scanlines = align(Height/2, 16)
+ * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096)
+ * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096)
+ * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64)
+ * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16)
+ * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096)
+ * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64)
+ * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16)
+ * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096)
+ * Extradata = 8k
+ */
+ COLOR_FMT_NV12_BPP10_UBWC,
+};
+
+static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
+{
+ (void)height;
+ (void)width;
+
+ /*
+ * In the future, calculate the size based on the w/h but just
+ * hardcode it for now since 8K satisfies all current usecases.
+ */
+ return 8 * 1024;
+}
+
+static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
+{
+ unsigned int alignment, stride = 0;
+ if (!width)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV21:
+ case COLOR_FMT_NV12:
+ case COLOR_FMT_NV12_MVTB:
+ case COLOR_FMT_NV12_UBWC:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width, alignment);
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width * 4/3, alignment);
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return stride;
+}
+
+static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width)
+{
+ unsigned int alignment, stride = 0;
+ if (!width)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV21:
+ case COLOR_FMT_NV12:
+ case COLOR_FMT_NV12_MVTB:
+ case COLOR_FMT_NV12_UBWC:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width, alignment);
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ alignment = 128;
+ stride = MSM_MEDIA_ALIGN(width * 4/3, alignment);
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return stride;
+}
+
+static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
+{
+ unsigned int alignment, sclines = 0;
+ if (!height)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV21:
+ case COLOR_FMT_NV12:
+ case COLOR_FMT_NV12_MVTB:
+ case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ alignment = 32;
+ sclines = MSM_MEDIA_ALIGN(height, alignment);
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return sclines;
+}
+
+static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
+{
+ unsigned int alignment, sclines = 0;
+ if (!height)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV21:
+ case COLOR_FMT_NV12:
+ case COLOR_FMT_NV12_MVTB:
+ case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ alignment = 16;
+ sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment);
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return sclines;
+}
+
+static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width)
+{
+ int y_tile_width = 0, y_meta_stride = 0;
+
+ if (!width)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV12_UBWC:
+ y_tile_width = 32;
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ y_tile_width = 48;
+ break;
+ default:
+ goto invalid_input;
+ }
+
+ y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width);
+ y_meta_stride = MSM_MEDIA_ALIGN(y_meta_stride, 64);
+
+invalid_input:
+ return y_meta_stride;
+}
+
+static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height)
+{
+ int y_tile_height = 0, y_meta_scanlines = 0;
+
+ if (!height)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV12_UBWC:
+ y_tile_height = 8;
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ y_tile_height = 4;
+ break;
+ default:
+ goto invalid_input;
+ }
+
+ y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height);
+ y_meta_scanlines = MSM_MEDIA_ALIGN(y_meta_scanlines, 16);
+
+invalid_input:
+ return y_meta_scanlines;
+}
+
+static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width)
+{
+ int uv_tile_width = 0, uv_meta_stride = 0;
+
+ if (!width)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV12_UBWC:
+ uv_tile_width = 16;
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ uv_tile_width = 24;
+ break;
+ default:
+ goto invalid_input;
+ }
+
+ uv_meta_stride = MSM_MEDIA_ROUNDUP(width, uv_tile_width);
+ uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64);
+
+invalid_input:
+ return uv_meta_stride;
+}
+
+static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height)
+{
+ int uv_tile_height = 0, uv_meta_scanlines = 0;
+
+ if (!height)
+ goto invalid_input;
+
+ switch (color_fmt) {
+ case COLOR_FMT_NV12_UBWC:
+ uv_tile_height = 8;
+ break;
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ uv_tile_height = 4;
+ break;
+ default:
+ goto invalid_input;
+ }
+
+ uv_meta_scanlines = MSM_MEDIA_ROUNDUP(height, uv_tile_height);
+ uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16);
+
+invalid_input:
+ return uv_meta_scanlines;
+}
+
+static inline unsigned int VENUS_BUFFER_SIZE(
+ int color_fmt, int width, int height)
+{
+ const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height);
+ unsigned int uv_alignment = 0, size = 0;
+ unsigned int y_plane, uv_plane, y_stride,
+ uv_stride, y_sclines, uv_sclines;
+ unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0;
+ unsigned int y_meta_stride = 0, y_meta_scanlines = 0;
+ unsigned int uv_meta_stride = 0, uv_meta_scanlines = 0;
+ unsigned int y_meta_plane = 0, uv_meta_plane = 0;
+
+ if (!width || !height)
+ goto invalid_input;
+
+ y_stride = VENUS_Y_STRIDE(color_fmt, width);
+ uv_stride = VENUS_UV_STRIDE(color_fmt, width);
+ y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
+ uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
+ switch (color_fmt) {
+ case COLOR_FMT_NV21:
+ case COLOR_FMT_NV12:
+ uv_alignment = 4096;
+ y_plane = y_stride * y_sclines;
+ uv_plane = uv_stride * uv_sclines + uv_alignment;
+ size = y_plane + uv_plane + extra_size;
+ size = MSM_MEDIA_ALIGN(size, 4096);
+ break;
+ case COLOR_FMT_NV12_MVTB:
+ uv_alignment = 4096;
+ y_plane = y_stride * y_sclines;
+ uv_plane = uv_stride * uv_sclines + uv_alignment;
+ size = y_plane + uv_plane;
+ size = 2 * size + extra_size;
+ size = MSM_MEDIA_ALIGN(size, 4096);
+ break;
+ case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_NV12_BPP10_UBWC:
+ y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
+ uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
+ y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
+ y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height);
+ y_meta_plane = MSM_MEDIA_ALIGN(
+ y_meta_stride * y_meta_scanlines, 4096);
+ uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
+ uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height);
+ uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride *
+ uv_meta_scanlines, 4096);
+
+ size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
+ uv_meta_plane + extra_size;
+ size = MSM_MEDIA_ALIGN(size, 4096);
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return size;
+}
+
+static inline unsigned int VENUS_VIEW2_OFFSET(
+ int color_fmt, int width, int height)
+{
+ unsigned int offset = 0;
+ unsigned int y_plane, uv_plane, y_stride,
+ uv_stride, y_sclines, uv_sclines;
+ if (!width || !height)
+ goto invalid_input;
+
+ y_stride = VENUS_Y_STRIDE(color_fmt, width);
+ uv_stride = VENUS_UV_STRIDE(color_fmt, width);
+ y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
+ uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
+ switch (color_fmt) {
+ case COLOR_FMT_NV12_MVTB:
+ y_plane = y_stride * y_sclines;
+ uv_plane = uv_stride * uv_sclines;
+ offset = y_plane + uv_plane;
+ break;
+ default:
+ break;
+ }
+invalid_input:
+ return offset;
+}
+
+#endif
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
new file mode 100644
index 000000000000..40a39e693bb4
--- /dev/null
+++ b/include/media/msm_vidc.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012-2014, 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/poll.h>
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#ifdef CONFIG_ION
+#include <linux/msm_ion.h>
+#endif
+#include <uapi/media/msm_vidc.h>
+#include <uapi/media/msm-v4l2-controls.h>
+
+#define HAL_BUFFER_MAX 0xb
+
+/*For backward compatibility*/
+#ifndef ion_phys_addr_t
+#define ion_phys_addr_t dma_addr_t
+#endif
+
+enum smem_type {
+ SMEM_ION,
+ SMEM_DMA,
+};
+
+enum smem_prop {
+#ifdef CONFIG_ION
+ SMEM_CACHED = ION_FLAG_CACHED,
+ SMEM_SECURE = ION_FLAG_SECURE,
+#else
+ SMEM_CACHED = BIT(0),
+ SMEM_SECURE = BIT(1),
+#endif
+};
+
+/* NOTE: if you change this enum you MUST update the
+ * "buffer-type-tz-usage-table" for any affected target
+ * in arch/arm/boot/dts/<arch>.dtsi
+ */
+enum hal_buffer {
+ HAL_BUFFER_NONE = 0x0,
+ HAL_BUFFER_INPUT = 0x1,
+ HAL_BUFFER_OUTPUT = 0x2,
+ HAL_BUFFER_OUTPUT2 = 0x4,
+ HAL_BUFFER_EXTRADATA_INPUT = 0x8,
+ HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
+ HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
+ HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
+ HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
+ HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
+ HAL_BUFFER_INTERNAL_PERSIST = 0x200,
+ HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
+};
+
+struct dma_mapping_info {
+ struct device *dev;
+ struct dma_iommu_mapping *mapping;
+ struct sg_table *table;
+ struct dma_buf_attachment *attach;
+ struct dma_buf *buf;
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ ion_phys_addr_t device_addr;
+ unsigned long flags;
+ void *smem_priv;
+ enum hal_buffer buffer_type;
+ struct dma_mapping_info mapping_info;
+};
+
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+enum core_id {
+ MSM_VIDC_CORE_VENUS = 0,
+ MSM_VIDC_CORE_Q6,
+ MSM_VIDC_CORES_MAX,
+};
+enum session_type {
+ MSM_VIDC_ENCODER = 0,
+ MSM_VIDC_DECODER,
+ MSM_VIDC_MAX_DEVICES,
+};
+void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_close(void *instance);
+int msm_vidc_suspend(int core_id);
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *pt);
+int msm_vidc_subscribe_event(void *instance,
+ const struct v4l2_event_subscription *sub);
+int msm_vidc_unsubscribe_event(void *instance,
+ const struct v4l2_event_subscription *sub);
+int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
+int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
+int msm_vidc_mmap(void* instance, struct vm_area_struct *vma);
+int msm_vidc_querybuf(void *instance, struct v4l2_buffer *b);
+
+#endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index bd2cec2d6c3d..c91aefa9cab7 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -18,6 +18,8 @@
#include <linux/videodev2.h>
#include <linux/dma-buf.h>
+#define VB2_MAX_FRAME 64
+
struct vb2_alloc_ctx;
struct vb2_fileio_data;
struct vb2_threadio_data;
@@ -411,7 +413,7 @@ struct vb2_queue {
/* private: internal use only */
struct mutex mmap_lock;
enum v4l2_memory memory;
- struct vb2_buffer *bufs[VIDEO_MAX_FRAME];
+ struct vb2_buffer *bufs[VB2_MAX_FRAME];
unsigned int num_buffers;
struct list_head queued_list;
diff --git a/include/soc/qcom/ocmem.h b/include/soc/qcom/ocmem.h
new file mode 100644
index 000000000000..2252e77d2490
--- /dev/null
+++ b/include/soc/qcom/ocmem.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2012,2014, 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.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/err.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE SZ_4K
+
+struct ocmem_notifier;
+
+struct ocmem_buf {
+ unsigned long addr;
+ unsigned long len;
+};
+
+struct ocmem_buf_attr {
+ unsigned long paddr;
+ unsigned long len;
+};
+
+struct ocmem_chunk {
+ bool ro;
+ unsigned long ddr_paddr;
+ unsigned long size;
+};
+
+struct ocmem_map_list {
+ unsigned num_chunks;
+ struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+enum ocmem_power_state {
+ OCMEM_OFF = 0x0,
+ OCMEM_RETENTION,
+ OCMEM_ON,
+ OCMEM_MAX = OCMEM_ON,
+};
+
+struct ocmem_resource {
+ unsigned resource_id;
+ unsigned num_keys;
+ unsigned int *keys;
+};
+
+struct ocmem_vectors {
+ unsigned num_resources;
+ struct ocmem_resource *r;
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+ /* GMEM clients */
+ OCMEM_GRAPHICS = 0x0,
+ /* TCMEM clients */
+ OCMEM_VIDEO,
+ OCMEM_CAMERA,
+ /* Dummy Clients */
+ OCMEM_HP_AUDIO,
+ OCMEM_VOICE,
+ /* IMEM Clients */
+ OCMEM_LP_AUDIO,
+ OCMEM_SENSORS,
+ OCMEM_OTHER_OS,
+ OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+ OCMEM_MAP_DONE = 1,
+ OCMEM_MAP_FAIL,
+ OCMEM_UNMAP_DONE,
+ OCMEM_UNMAP_FAIL,
+ OCMEM_ALLOC_GROW,
+ OCMEM_ALLOC_SHRINK,
+ OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+#ifdef CONFIG_MSM_OCMEM
+/* Notification APIs */
+struct ocmem_notifier *ocmem_notifier_register(int client_id,
+ struct notifier_block *nb);
+
+int ocmem_notifier_unregister(struct ocmem_notifier *notif_hndl,
+ struct notifier_block *nb);
+
+/* Obtain the maximum quota for the client */
+unsigned long get_max_quota(int client_id);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+ unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+/* Transfer APIs */
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list);
+
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list);
+
+int ocmem_drop(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list);
+
+int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+ unsigned long dst_phys_addr);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+
+/* Power Control APIs */
+int ocmem_set_power_state(int client_id, struct ocmem_buf *buf,
+ enum ocmem_power_state new_state);
+
+enum ocmem_power_state ocmem_get_power_state(int client_id,
+ struct ocmem_buf *buf);
+
+struct ocmem_vectors *ocmem_get_vectors(int client_id,
+ struct ocmem_buf *buf);
+
+#else
+/* Notification APIs */
+static inline struct ocmem_notifier *ocmem_notifier_register
+ (int client_id, struct notifier_block *nb)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline int ocmem_notifier_unregister(struct ocmem_notifier *notif_hndl,
+ struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+/* Obtain the maximum quota for the client */
+static inline unsigned long get_max_quota(int client_id)
+{
+ return 0;
+}
+
+/* Allocation APIs */
+static inline struct ocmem_buf *ocmem_allocate(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nowait(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nb(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_range(int client_id,
+ unsigned long min, unsigned long goal, unsigned long step)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+/* Free APIs */
+static inline int ocmem_free(int client_id, struct ocmem_buf *buf)
+{
+ return -ENODEV;
+}
+
+/* Dynamic Resize APIs */
+static inline int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size)
+{
+ return -ENODEV;
+}
+
+/* Transfer APIs */
+static inline int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+ unsigned long dst_phys_addr)
+{
+ return -ENODEV;
+}
+
+/* Priority Enforcement APIs */
+static inline int ocmem_evict(int client_id)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_restore(int client_id)
+{
+ return -ENODEV;
+}
+
+/* Power Control APIs */
+static inline int ocmem_set_power_state(int client_id,
+ struct ocmem_buf *buf, enum ocmem_power_state new_state)
+{
+ return -ENODEV;
+}
+
+static inline enum ocmem_power_state ocmem_get_power_state(int client_id,
+ struct ocmem_buf *buf)
+{
+ return -ENODEV;
+}
+static inline struct ocmem_vectors *ocmem_get_vectors(int client_id,
+ struct ocmem_buf *buf)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
+#endif
diff --git a/include/trace/events/msm_vidc.h b/include/trace/events/msm_vidc.h
new file mode 100644
index 000000000000..74283aebb2db
--- /dev/null
+++ b/include/trace/events/msm_vidc.h
@@ -0,0 +1,315 @@
+/* Copyright (c) 2014, 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.
+ *
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msm_vidc
+
+#if !defined(_TRACE_MSM_VIDC_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSM_VIDC_H
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(msm_v4l2_vidc,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy),
+
+ TP_STRUCT__entry(
+ __field(char *, dummy)
+ ),
+
+ TP_fast_assign(
+ __entry->dummy = dummy;
+ ),
+
+ TP_printk("%s", __entry->dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_open_start,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_open_end,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_close_start,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_close_end,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_fw_load_start,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc, msm_v4l2_vidc_fw_load_end,
+
+ TP_PROTO(char *dummy),
+
+ TP_ARGS(dummy)
+);
+
+DECLARE_EVENT_CLASS(msm_vidc_common,
+
+ TP_PROTO(void *instp, int old_state, int new_state),
+
+ TP_ARGS(instp, old_state, new_state),
+
+ TP_STRUCT__entry(
+ __field(void *, instp)
+ __field(int, old_state)
+ __field(int, new_state)
+ ),
+
+ TP_fast_assign(
+ __entry->instp = instp;
+ __entry->old_state = old_state;
+ __entry->new_state = new_state;
+ ),
+
+ TP_printk("Moved inst: %p from 0x%x to 0x%x",
+ __entry->instp,
+ __entry->old_state,
+ __entry->new_state)
+);
+
+DEFINE_EVENT(msm_vidc_common, msm_vidc_common_state_change,
+
+ TP_PROTO(void *instp, int old_state, int new_state),
+
+ TP_ARGS(instp, old_state, new_state)
+);
+
+DECLARE_EVENT_CLASS(venus_hfi_var,
+
+ TP_PROTO(u32 cp_start, u32 cp_size,
+ u32 cp_nonpixel_start, u32 cp_nonpixel_size),
+
+ TP_ARGS(cp_start, cp_size, cp_nonpixel_start, cp_nonpixel_size),
+
+ TP_STRUCT__entry(
+ __field(u32, cp_start)
+ __field(u32, cp_size)
+ __field(u32, cp_nonpixel_start)
+ __field(u32, cp_nonpixel_size)
+ ),
+
+ TP_fast_assign(
+ __entry->cp_start = cp_start;
+ __entry->cp_size = cp_size;
+ __entry->cp_nonpixel_start = cp_nonpixel_start;
+ __entry->cp_nonpixel_size = cp_nonpixel_size;
+ ),
+
+ TP_printk(
+ "TZBSP_MEM_PROTECT_VIDEO_VAR done, cp_start : 0x%x, cp_size : 0x%x, cp_nonpixel_start : 0x%x, cp_nonpixel_size : 0x%x",
+ __entry->cp_start,
+ __entry->cp_size,
+ __entry->cp_nonpixel_start,
+ __entry->cp_nonpixel_size)
+);
+
+DEFINE_EVENT(venus_hfi_var, venus_hfi_var_done,
+
+ TP_PROTO(u32 cp_start, u32 cp_size,
+ u32 cp_nonpixel_start, u32 cp_nonpixel_size),
+
+ TP_ARGS(cp_start, cp_size, cp_nonpixel_start, cp_nonpixel_size)
+);
+
+DECLARE_EVENT_CLASS(msm_v4l2_vidc_buffer_events,
+
+ TP_PROTO(char *event_type, u32 device_addr, int64_t timestamp,
+ u32 alloc_len, u32 filled_len, u32 offset),
+
+ TP_ARGS(event_type, device_addr, timestamp, alloc_len,
+ filled_len, offset),
+
+ TP_STRUCT__entry(
+ __field(char *, event_type)
+ __field(u32, device_addr)
+ __field(int64_t, timestamp)
+ __field(u32, alloc_len)
+ __field(u32, filled_len)
+ __field(u32, offset)
+ ),
+
+ TP_fast_assign(
+ __entry->event_type = event_type;
+ __entry->device_addr = device_addr;
+ __entry->timestamp = timestamp;
+ __entry->alloc_len = alloc_len;
+ __entry->filled_len = filled_len;
+ __entry->offset = offset;
+ ),
+
+ TP_printk(
+ "%s, device_addr : 0x%x, timestamp : %lld, alloc_len : 0x%x, filled_len : 0x%x, offset : 0x%x",
+ __entry->event_type,
+ __entry->device_addr,
+ __entry->timestamp,
+ __entry->alloc_len,
+ __entry->filled_len,
+ __entry->offset)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc_buffer_events, msm_v4l2_vidc_buffer_event_start,
+
+ TP_PROTO(char *event_type, u32 device_addr, int64_t timestamp,
+ u32 alloc_len, u32 filled_len, u32 offset),
+
+ TP_ARGS(event_type, device_addr, timestamp, alloc_len,
+ filled_len, offset)
+);
+
+DEFINE_EVENT(msm_v4l2_vidc_buffer_events, msm_v4l2_vidc_buffer_event_end,
+
+ TP_PROTO(char *event_type, u32 device_addr, int64_t timestamp,
+ u32 alloc_len, u32 filled_len, u32 offset),
+
+ TP_ARGS(event_type, device_addr, timestamp, alloc_len,
+ filled_len, offset)
+);
+
+DECLARE_EVENT_CLASS(msm_smem_buffer_ion_ops,
+
+ TP_PROTO(char *buffer_op, u32 buffer_type, u32 heap_mask,
+ size_t size, u32 align, u32 flags, int map_kernel),
+
+ TP_ARGS(buffer_op, buffer_type, heap_mask, size, align,
+ flags, map_kernel),
+
+ TP_STRUCT__entry(
+ __field(char *, buffer_op)
+ __field(u32, buffer_type)
+ __field(u32, heap_mask)
+ __field(u32, size)
+ __field(u32, align)
+ __field(u32, flags)
+ __field(int, map_kernel)
+ ),
+
+ TP_fast_assign(
+ __entry->buffer_op = buffer_op;
+ __entry->buffer_type = buffer_type;
+ __entry->heap_mask = heap_mask;
+ __entry->size = size;
+ __entry->align = align;
+ __entry->flags = flags;
+ __entry->map_kernel = map_kernel;
+ ),
+
+ TP_printk(
+ "%s, buffer_type : 0x%x, heap_mask : 0x%x, size : 0x%x, align : 0x%x, flags : 0x%x, map_kernel : %d",
+ __entry->buffer_op,
+ __entry->buffer_type,
+ __entry->heap_mask,
+ __entry->size,
+ __entry->align,
+ __entry->flags,
+ __entry->map_kernel)
+);
+
+DEFINE_EVENT(msm_smem_buffer_ion_ops, msm_smem_buffer_ion_op_start,
+
+ TP_PROTO(char *buffer_op, u32 buffer_type, u32 heap_mask,
+ size_t size, u32 align, u32 flags, int map_kernel),
+
+ TP_ARGS(buffer_op, buffer_type, heap_mask, size, align,
+ flags, map_kernel)
+);
+
+DEFINE_EVENT(msm_smem_buffer_ion_ops, msm_smem_buffer_ion_op_end,
+
+ TP_PROTO(char *buffer_op, u32 buffer_type, u32 heap_mask,
+ size_t size, u32 align, u32 flags, int map_kernel),
+
+ TP_ARGS(buffer_op, buffer_type, heap_mask, size, align,
+ flags, map_kernel)
+);
+
+DECLARE_EVENT_CLASS(msm_smem_buffer_iommu_ops,
+
+ TP_PROTO(char *buffer_op, int domain_num, int partition_num,
+ unsigned long align, unsigned long iova,
+ unsigned long buffer_size),
+
+ TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size),
+
+ TP_STRUCT__entry(
+ __field(char *, buffer_op)
+ __field(int, domain_num)
+ __field(int, partition_num)
+ __field(unsigned long, align)
+ __field(unsigned long, iova)
+ __field(unsigned long, buffer_size)
+ ),
+
+ TP_fast_assign(
+ __entry->buffer_op = buffer_op;
+ __entry->domain_num = domain_num;
+ __entry->partition_num = partition_num;
+ __entry->align = align;
+ __entry->iova = iova;
+ __entry->buffer_size = buffer_size;
+ ),
+
+ TP_printk(
+ "%s, domain : %d, partition : %d, align : %lx, iova : 0x%lx, buffer_size=%lx",
+ __entry->buffer_op,
+ __entry->domain_num,
+ __entry->partition_num,
+ __entry->align,
+ __entry->iova,
+ __entry->buffer_size)
+);
+
+DEFINE_EVENT(msm_smem_buffer_iommu_ops, msm_smem_buffer_iommu_op_start,
+
+ TP_PROTO(char *buffer_op, int domain_num, int partition_num,
+ unsigned long align, unsigned long iova,
+ unsigned long buffer_size),
+
+ TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size)
+);
+
+DEFINE_EVENT(msm_smem_buffer_iommu_ops, msm_smem_buffer_iommu_op_end,
+
+ TP_PROTO(char *buffer_op, int domain_num, int partition_num,
+ unsigned long align, unsigned long iova,
+ unsigned long buffer_size),
+
+ TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size)
+);
+
+#endif
+
+#include <trace/define_trace.h>
diff --git a/include/uapi/Kbuild b/include/uapi/Kbuild
index 245aa6e05e6a..aeb3366db4fc 100644
--- a/include/uapi/Kbuild
+++ b/include/uapi/Kbuild
@@ -13,3 +13,4 @@ header-y += drm/
header-y += xen/
header-y += scsi/
header-y += misc/
+header-y += media/
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 9f6e108ff4a0..5c6348918483 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -365,6 +365,7 @@ enum v4l2_mpeg_video_bitrate_mode {
enum v4l2_mpeg_video_header_mode {
V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0,
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1,
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME = 2,
};
#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217)
@@ -376,6 +377,7 @@ enum v4l2_mpeg_video_multi_slice_mode {
V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0,
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1,
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_GOB = 3,
};
#define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222)
#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223)
@@ -421,6 +423,7 @@ enum v4l2_mpeg_video_h264_level {
V4L2_MPEG_VIDEO_H264_LEVEL_4_2 = 13,
V4L2_MPEG_VIDEO_H264_LEVEL_5_0 = 14,
V4L2_MPEG_VIDEO_H264_LEVEL_5_1 = 15,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_2 = 16,
};
#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360)
#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361)
@@ -449,6 +452,7 @@ enum v4l2_mpeg_video_h264_profile {
V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA = 14,
V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH = 15,
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16,
+ V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH = 17,
};
#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364)
#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index fbdc3602ee27..47b7289896c0 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -442,6 +442,11 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */
+/* UBWC 8-bit Y/CbCr 4:2:0 */
+#define V4L2_PIX_FMT_NV12_UBWC v4l2_fourcc('Q', '1', '2', '8')
+/* UBWC 10-bit Y/CbCr 4:2:0 */
+#define V4L2_PIX_FMT_NV12_TP10_UBWC v4l2_fourcc('Q', '1', '2', 'A')
+
/* two non contiguous planes - one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */
@@ -500,6 +505,10 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
+#define V4L2_PIX_FMT_DIVX_311 v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311 */
+#define V4L2_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX */
+#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_HEVC_HYBRID v4l2_fourcc('H', 'V', 'C', 'H')
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
new file mode 100644
index 000000000000..684a730658b5
--- /dev/null
+++ b/include/uapi/media/Kbuild
@@ -0,0 +1,2 @@
+header-y += msm_vidc.h
+header-y += msm-v4l2-controls.h
diff --git a/include/uapi/media/msm-v4l2-controls.h b/include/uapi/media/msm-v4l2-controls.h
new file mode 100644
index 000000000000..0b5639faa4c2
--- /dev/null
+++ b/include/uapi/media/msm-v4l2-controls.h
@@ -0,0 +1,455 @@
+#ifndef __MSM_V4L2_CONTROLS_H__
+#define __MSM_V4L2_CONTROLS_H__
+
+#include <linux/v4l2-controls.h>
+
+/* MPEG-class control IDs specific to the msm_vidc driver */
+#define V4L2_CID_MPEG_MSM_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+0)
+#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+1)
+#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+2)
+#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+3)
+enum v4l2_mpeg_vidc_video_divx_format_type {
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+4)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+5)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+6)
+enum v4l2_mpeg_vidc_video_stream_format {
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES = 0,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER = 1,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH = 2,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH = 3,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+7)
+enum v4l2_mpeg_vidc_video_output_order {
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0,
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE (V4L2_CID_MPEG_MSM_VIDC_BASE+8)
+#define V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD (V4L2_CID_MPEG_MSM_VIDC_BASE+9)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+10)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+11)
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME (V4L2_CID_MPEG_MSM_VIDC_BASE+12)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL (V4L2_CID_MPEG_MSM_VIDC_BASE+13)
+enum v4l2_mpeg_vidc_video_rate_control {
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ROTATION (V4L2_CID_MPEG_MSM_VIDC_BASE+14)
+enum v4l2_mpeg_vidc_video_rotation {
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180 = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270 = 3,
+};
+#define MSM_VIDC_BASE V4L2_CID_MPEG_MSM_VIDC_BASE
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL (MSM_VIDC_BASE+15)
+enum v4l2_mpeg_vidc_h264_cabac_model {
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0 = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2 = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE (MSM_VIDC_BASE+16)
+enum v4l2_mpeg_vidc_video_intra_refresh_mode {
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 4,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+17)
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE+18)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+19)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+20)
+enum v4l2_mpeg_vidc_video_h263_profile {
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+21)
+enum v4l2_mpeg_vidc_video_h263_level {
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
+enum v4l2_mpeg_vidc_video_h264_au_delimiter {
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_sync_frame_decode {
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE = 1
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE (V4L2_CID_MPEG_MSM_VIDC_BASE+24)
+#define V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 25)
+enum v4l2_mpeg_vidc_extradata {
+ V4L2_MPEG_VIDC_EXTRADATA_NONE = 0,
+ V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1,
+ V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2,
+ V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3,
+ V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4,
+ V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5,
+ V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7,
+ V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW = 8,
+ V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 9,
+ V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO = 10,
+ V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB = 11,
+ V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER = 12,
+ V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP = 13,
+ V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM = 14,
+ V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO = 15,
+ V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP = 16,
+ V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA = 17,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP = 18,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO = 19,
+ V4L2_MPEG_VIDC_EXTRADATA_LTR = 20,
+ V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI = 21,
+};
+
+#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
+enum v4l2_mpeg_vidc_perf_level {
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL = 0,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 1,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 27)
+
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 28)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 29)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 30)
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 31)
+enum v4l2_mpeg_vidc_video_alloc_mode_type {
+ V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
+ V4L2_MPEG_VIDC_VIDEO_RING = 1,
+ V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 32)
+enum v4l2_mpeg_vidc_video_assembly {
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 33)
+enum v4l2_mpeg_vidc_video_vp8_profile_level {
+ V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 34)
+enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 35)
+enum v4l2_mpeg_vidc_video_preserve_text_quality {
+ V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+enum v4l2_mpeg_vidc_video_deinterlace {
+ V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 38)
+enum v4l2_mpeg_vidc_video_decoder_multi_stream {
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 39)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+40)
+enum v4l2_mpeg_vidc_video_mpeg2_level {
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3 = 3,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+41)
+enum v4l2_mpeg_vidc_video_mpeg2_profile {
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN = 1,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422 = 2,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE = 3,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE = 4,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH = 5,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 42)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 43)
+enum v4l2_mpeg_vidc_video_mvc_layout {
+ V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0,
+ V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 44)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 45)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 46)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 47)
+
+enum v4l2_mpeg_vidc_video_ltrmode {
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL = 1,
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 48)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 49)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 50)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 51)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 52)
+enum v4l2_mpeg_vidc_video_rate_control_timestamp_mode {
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR = 0,
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 53)
+enum vl42_mpeg_vidc_video_enable_initial_qp {
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME = 0x1,
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME = 0x2,
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 54)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 55)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 56)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 57)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 58)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 59)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 60)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 61)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 62)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 63)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 64)
+
+enum vl42_mpeg_vidc_video_vpx_error_resilience {
+ V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 65)
+enum v4l2_mpeg_video_hevc_profile {
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN = 0,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10 = 1,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 66)
+enum v4l2_mpeg_video_hevc_level {
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1 = 0,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2 = 3,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1 = 4,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1 = 5,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3 = 6,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3 = 7,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1 = 8,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1 = 9,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4 = 10,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4 = 11,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1 = 12,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1 = 13,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5 = 14,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5 = 15,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1 = 16,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1 = 17,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2 = 18,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2 = 19,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6 = 20,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6 = 21,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1 = 22,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1 = 23,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2 = 24,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2 = 25,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 67)
+
+enum vl42_mpeg_vidc_video_h264_svc_nal {
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 68)
+
+enum v4l2_mpeg_vidc_video_perf_mode {
+ V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1,
+ V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 69)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 70)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2 \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 71)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 72)
+
+/* Vendor extensions */
+#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x10000
+#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x20000
+#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x40000
+#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x80000 /*Image is a IDR-frame*/
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x100000
+#define V4L2_QCOM_BUF_DATA_CORRUPT 0x200000
+#define V4L2_QCOM_BUF_DROP_FRAME 0x400000
+#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x800000
+#define V4L2_QCOM_BUF_FLAG_EOS 0x1000000
+#define V4L2_QCOM_BUF_TS_DISCONTINUITY 0x2000000
+#define V4L2_QCOM_BUF_TS_ERROR 0x4000000
+#define V4L2_QCOM_BUF_FLAG_READONLY 0x8000000
+#define V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND 0x10000000
+#define V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP 0x20000000
+#define V4L2_MSM_BUF_FLAG_MBAFF 0x40000000
+
+/* Capabilities */
+#define V4L2_CAP_QCOM_FRAMESKIP 0x2000 /* frame skipping is supported */
+
+struct v4l2_qcom_frameskip {
+ __u64 maxframeinterval;
+ __u8 fpsvariance;
+};
+
+/* Encoder commands */
+#define V4L2_ENC_QCOM_CMD_FLUSH (4)
+
+/* Decoder commands */
+#define V4L2_DEC_QCOM_CMD_FLUSH (4)
+
+/* Flags for V4L2_DEC_QCOM_CMD_FLUSH */
+#define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT (1 << 0)
+#define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
+#define V4L2_QCOM_CMD_FLUSH_OUTPUT (1 << 0)
+#define V4L2_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
+/* Events */
+#define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_MSM_VIDC_START + 1)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 2)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 3)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4)
+#define V4L2_EVENT_MSM_VIDC_SYS_ERROR (V4L2_EVENT_MSM_VIDC_START + 5)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \
+ (V4L2_EVENT_MSM_VIDC_START + 6)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
+ (V4L2_EVENT_MSM_VIDC_START + 7)
+#define V4L2_EVENT_MSM_VIDC_HW_OVERLOAD (V4L2_EVENT_MSM_VIDC_START + 8)
+#define V4L2_EVENT_MSM_VIDC_MAX_CLIENTS (V4L2_EVENT_MSM_VIDC_START + 9)
+#define V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED (V4L2_EVENT_MSM_VIDC_START + 10)
+
+#endif/* __MSM_V4L2_CONTROLS_H__ */
diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h
new file mode 100644
index 000000000000..6fa53ad7997b
--- /dev/null
+++ b/include/uapi/media/msm_vidc.h
@@ -0,0 +1,154 @@
+#ifndef __MSM_VIDC_H__
+#define __MSM_VIDC_H__
+
+#include <linux/types.h>
+
+struct msm_vidc_extradata_header {
+ unsigned int size;
+ unsigned int:32; /** Keeping binary compatibility */
+ unsigned int:32; /* with firmware and OpenMAX IL **/
+ unsigned int type; /* msm_vidc_extradata_type */
+ unsigned int data_size;
+ unsigned char data[1];
+};
+struct msm_vidc_interlace_payload {
+ unsigned int format;
+};
+struct msm_vidc_framerate_payload {
+ unsigned int frame_rate;
+};
+struct msm_vidc_ts_payload {
+ unsigned int timestamp_lo;
+ unsigned int timestamp_hi;
+};
+struct msm_vidc_concealmb_payload {
+ unsigned int num_mbs;
+};
+struct msm_vidc_recoverysei_payload {
+ unsigned int flags;
+};
+struct msm_vidc_aspect_ratio_payload {
+ unsigned int size;
+ unsigned int version;
+ unsigned int port_index;
+ unsigned int aspect_width;
+ unsigned int aspect_height;
+};
+struct msm_vidc_mpeg2_seqdisp_payload {
+ unsigned int video_format;
+ unsigned int color_descp;
+ unsigned int color_primaries;
+ unsigned int transfer_char;
+ unsigned int matrix_coeffs;
+ unsigned int disp_width;
+ unsigned int disp_height;
+};
+struct msm_vidc_input_crop_payload {
+ unsigned int size;
+ unsigned int version;
+ unsigned int port_index;
+ unsigned int left;
+ unsigned int top;
+ unsigned int width;
+ unsigned int height;
+};
+struct msm_vidc_digital_zoom_payload {
+ unsigned int size;
+ unsigned int version;
+ unsigned int port_index;
+ unsigned int zoom_width;
+ unsigned int zoom_height;
+};
+struct msm_vidc_extradata_index {
+ unsigned int type;
+ union {
+ struct msm_vidc_input_crop_payload input_crop;
+ struct msm_vidc_digital_zoom_payload digital_zoom;
+ struct msm_vidc_aspect_ratio_payload aspect_ratio;
+ };
+};
+struct msm_vidc_panscan_window {
+ unsigned int panscan_height_offset;
+ unsigned int panscan_width_offset;
+ unsigned int panscan_window_width;
+ unsigned int panscan_window_height;
+};
+struct msm_vidc_panscan_window_payload {
+ unsigned int num_panscan_windows;
+ struct msm_vidc_panscan_window wnd[1];
+};
+struct msm_vidc_stream_userdata_payload {
+ unsigned int type;
+ unsigned int data[1];
+};
+struct msm_vidc_frame_qp_payload {
+ unsigned int frame_qp;
+};
+struct msm_vidc_frame_bits_info_payload {
+ unsigned int frame_bits;
+ unsigned int header_bits;
+};
+struct msm_vidc_s3d_frame_packing_payload {
+ unsigned int fpa_id;
+ unsigned int cancel_flag;
+ unsigned int fpa_type;
+ unsigned int quin_cunx_flag;
+ unsigned int content_interprtation_type;
+ unsigned int spatial_flipping_flag;
+ unsigned int frame0_flipped_flag;
+ unsigned int field_views_flag;
+ unsigned int current_frame_is_frame0_flag;
+ unsigned int frame0_self_contained_flag;
+ unsigned int frame1_self_contained_flag;
+ unsigned int frame0_graid_pos_x;
+ unsigned int frame0_graid_pos_y;
+ unsigned int frame1_graid_pos_x;
+ unsigned int frame1_graid_pos_y;
+ unsigned int fpa_reserved_byte;
+ unsigned int fpa_repetition_period;
+ unsigned int fpa_extension_flag;
+};
+
+enum msm_vidc_extradata_type {
+ MSM_VIDC_EXTRADATA_NONE = 0x00000000,
+ MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001,
+ MSM_VIDC_EXTRADATA_INTERLACE_VIDEO = 0x00000002,
+ MSM_VIDC_EXTRADATA_VC1_FRAMEDISP = 0x00000003,
+ MSM_VIDC_EXTRADATA_VC1_SEQDISP = 0x00000004,
+ MSM_VIDC_EXTRADATA_TIMESTAMP = 0x00000005,
+ MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING = 0x00000006,
+ MSM_VIDC_EXTRADATA_FRAME_RATE = 0x00000007,
+ MSM_VIDC_EXTRADATA_PANSCAN_WINDOW = 0x00000008,
+ MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 0x00000009,
+ MSM_VIDC_EXTRADATA_MPEG2_SEQDISP = 0x0000000D,
+ MSM_VIDC_EXTRADATA_STREAM_USERDATA = 0x0000000E,
+ MSM_VIDC_EXTRADATA_FRAME_QP = 0x0000000F,
+ MSM_VIDC_EXTRADATA_FRAME_BITS_INFO = 0x00000010,
+ MSM_VIDC_EXTRADATA_INPUT_CROP = 0x0700000E,
+ MSM_VIDC_EXTRADATA_DIGITAL_ZOOM = 0x07000010,
+ MSM_VIDC_EXTRADATA_MULTISLICE_INFO = 0x7F100000,
+ MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
+ MSM_VIDC_EXTRADATA_INDEX = 0x7F100002,
+ MSM_VIDC_EXTRADATA_ASPECT_RATIO = 0x7F100003,
+ MSM_VIDC_EXTRADATA_METADATA_LTR = 0x7F100004,
+ MSM_VIDC_EXTRADATA_METADATA_FILLER = 0x7FE00002,
+ MSM_VIDC_EXTRADATA_METADATA_MBI = 0x7F100005,
+};
+enum msm_vidc_interlace_type {
+ MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE = 0x01,
+ MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
+ MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+ MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
+ MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+};
+enum msm_vidc_recovery_sei {
+ MSM_VIDC_FRAME_RECONSTRUCTION_INCORRECT = 0x0,
+ MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT = 0x01,
+ MSM_VIDC_FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT = 0x02,
+};
+enum msm_vidc_userdata_type {
+ MSM_VIDC_USERDATA_TYPE_FRAME = 0x1,
+ MSM_VIDC_USERDATA_TYPE_TOP_FIELD = 0x2,
+ MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD = 0x3,
+};
+#endif