linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/33] Qualcomm video decoder/encoder driver
@ 2023-07-28 13:23 Vikash Garodia
  2023-07-28 13:23 ` [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver Vikash Garodia
                   ` (35 more replies)
  0 siblings, 36 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This patch series introduces support for Qualcomm new video acceleration
hardware architecture, used for video stream decoding/encoding. This driver
is based on new communication protocol between video hardware and application
processor.

This driver comes with below capabilities:
- V4L2 complaint video driver with M2M and STREAMING capability.
- Supports H264, H265, VP9 decoders.
- Supports H264, H265 encoders.

This driver comes with below features:
- Centralized resource and memory management.
- Centralized management of core and instance states.
- Defines platform specific capabilities and features. As a results, it provides
  a single point of control to enable/disable a given feature depending on 
  specific platform capabilities.
- Handles hardware interdependent configurations. For a given configuration from
  client, the driver checks for hardware dependent configuration/s and updates
  the same.
- Handles multiple complex video scenarios involving state transitions - DRC,
  Drain, Seek, back to back DRC, DRC during Drain sequence, DRC during Seek
  sequence.
- Introduces a flexible way for driver to subscribe for any property with
  hardware. Hardware would inform driver with those subscribed property with any
  change in value.
- Introduces performance (clock and bus) model based on new hardware
  architecture.
- Introduces multi thread safe design to handle communication between client and
  hardware.
- Adapts encoder quality improvements available in new hardware architecture.
- Implements asynchronous communication with hardware to achieve better
  experience in low latency usecases.
- Supports multi stage hardware architecture for encode/decode.
- Output and capture planes are controlled independently. Thereby providing a
  way to reconfigure individual plane.
- Hardware packetization layer supports synchronization between configuration
  packet and data packet.
- Introduces a flexibility to receive a hardware response for a given command
  packet.
- Native hardware support of LAST flag which is mandatory to align with port
  reconfiguration and DRAIN sequence as per V4L guidelines.
- Native hardware support for drain sequence.

I think that the driver is in good shape for mainline kernel, and I hope the
review comments will help to improve it, so please do review, and make comments.

Dikshita Agarwal (17):
  iris: vidc: add core functions
  iris: add vidc wrapper file
  iris: vidc: add vb2 ops
  iris: vidc: add helpers for memory management
  iris: vidc: add helper functions for resource management
  iris: vidc: add helper functions for power management
  iris: add helpers for media format
  iris: vidc: add PIL functionality for video firmware
  iris: platform: add platform files
  iris: platform: sm8550: add capability file for sm8550
  iris: variant: add helper functions for register handling
  iris: variant: iris3: add iris3 specific ops
  iris: variant: iris3: add helpers for buffer size calculations
  iris: variant: iris3: add helper for bus and clock calculation
  iris: variant: iris: implement the logic to compute bus bandwidth
  iris: variant: iris3: implement logic to compute clock frequency
  iris: enable building of iris video driver

Vikash Garodia (16):
  MAINTAINERS: Add Qualcomm Iris video accelerator driver
  iris: vidc: add v4l2 wrapper file
  iris: vidc: define video core and instance context
  iris: iris: add video encoder files
  iris: vidc: add video decoder files
  iris: vidc: add control files
  iris: vidc: add helper functions
  iris: vidc: add helpers for state management
  iris: add vidc buffer files
  iris: vidc: define various structures and enum
  iris: vidc: hfi: add Host Firmware Interface (HFI)
  iris: vidc: hfi: add Host Firmware Interface (HFI) response handling
  iris: vidc: hfi: add helpers for handling shared queues
  iris: vidc: hfi: Add packetization layer
  iris: vidc: hfi: defines HFI properties and enums
  iris: vidc: add debug files

 MAINTAINERS                                        |   10 +
 drivers/media/platform/qcom/Kconfig                |    1 +
 drivers/media/platform/qcom/Makefile               |    1 +
 drivers/media/platform/qcom/iris/Kconfig           |   15 +
 drivers/media/platform/qcom/iris/Makefile          |   46 +
 .../iris/platform/common/inc/msm_vidc_platform.h   |  305 ++
 .../iris/platform/common/src/msm_vidc_platform.c   | 2499 ++++++++++++
 .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
 .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++
 .../iris/variant/common/inc/msm_vidc_variant.h     |   22 +
 .../iris/variant/common/src/msm_vidc_variant.c     |  163 +
 .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 +++++++
 .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
 .../qcom/iris/variant/iris3/inc/msm_vidc_iris3.h   |   15 +
 .../iris/variant/iris3/inc/msm_vidc_power_iris3.h  |   17 +
 .../iris/variant/iris3/inc/perf_static_model.h     |  229 ++
 .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 +++
 .../iris/variant/iris3/src/msm_vidc_bus_iris3.c    |  884 ++++
 .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  |  627 +++
 .../qcom/iris/variant/iris3/src/msm_vidc_iris3.c   |  954 +++++
 .../iris/variant/iris3/src/msm_vidc_power_iris3.c  |  345 ++
 .../media/platform/qcom/iris/vidc/inc/firmware.h   |   18 +
 .../platform/qcom/iris/vidc/inc/hfi_command.h      |  190 +
 .../media/platform/qcom/iris/vidc/inc/hfi_packet.h |   52 +
 .../platform/qcom/iris/vidc/inc/hfi_property.h     |  666 +++
 .../platform/qcom/iris/vidc/inc/msm_media_info.h   |  599 +++
 .../media/platform/qcom/iris/vidc/inc/msm_vdec.h   |   40 +
 .../media/platform/qcom/iris/vidc/inc/msm_venc.h   |   34 +
 .../media/platform/qcom/iris/vidc/inc/msm_vidc.h   |   60 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_buffer.h  |   32 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_control.h |   26 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_core.h    |  165 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   |  186 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_driver.h  |  352 ++
 .../platform/qcom/iris/vidc/inc/msm_vidc_inst.h    |  207 +
 .../qcom/iris/vidc/inc/msm_vidc_internal.h         |  787 ++++
 .../platform/qcom/iris/vidc/inc/msm_vidc_memory.h  |   83 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_power.h   |   94 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_state.h   |  102 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |   77 +
 .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |   39 +
 .../media/platform/qcom/iris/vidc/inc/resources.h  |  259 ++
 .../media/platform/qcom/iris/vidc/inc/venus_hfi.h  |   66 +
 .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |   89 +
 .../qcom/iris/vidc/inc/venus_hfi_response.h        |   26 +
 .../media/platform/qcom/iris/vidc/src/firmware.c   |  294 ++
 .../media/platform/qcom/iris/vidc/src/hfi_packet.c |  657 +++
 .../media/platform/qcom/iris/vidc/src/msm_vdec.c   | 2091 ++++++++++
 .../media/platform/qcom/iris/vidc/src/msm_venc.c   | 1484 +++++++
 .../media/platform/qcom/iris/vidc/src/msm_vidc.c   |  841 ++++
 .../platform/qcom/iris/vidc/src/msm_vidc_buffer.c  |  290 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_control.c |  824 ++++
 .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   |  581 +++
 .../platform/qcom/iris/vidc/src/msm_vidc_driver.c  | 4276 ++++++++++++++++++++
 .../platform/qcom/iris/vidc/src/msm_vidc_memory.c  |  448 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_power.c   |  560 +++
 .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   |  660 +++
 .../platform/qcom/iris/vidc/src/msm_vidc_state.c   | 1607 ++++++++
 .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    |  953 +++++
 .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     |  605 +++
 .../media/platform/qcom/iris/vidc/src/resources.c  | 1321 ++++++
 .../media/platform/qcom/iris/vidc/src/venus_hfi.c  | 1503 +++++++
 .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  |  537 +++
 .../qcom/iris/vidc/src/venus_hfi_response.c        | 1607 ++++++++
 64 files changed, 35357 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/Kconfig
 create mode 100644 drivers/media/platform/qcom/iris/Makefile
 create mode 100644 drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
 create mode 100644 drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
 create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
 create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/firmware.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/resources.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/firmware.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/resources.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 108+ messages in thread

* [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 22:48   ` Randy Dunlap
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
                   ` (34 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

Add an entry for Iris video encoder/decoder accelerator driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 3be1bdf..ea633b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17671,6 +17671,16 @@ T:	git git://linuxtv.org/media_tree.git
 F:	Documentation/devicetree/bindings/media/*venus*
 F:	drivers/media/platform/qcom/venus/
 
+QUALCOMM IRIS VIDEO ACCELERATOR DRIVER
+M:	Vikash Garodia <quic_vgarodia@quicinc.com>
+M:	Dikshita Agarwal <quic_dikshita@quicinc.com>
+L:	linux-media@vger.kernel.org
+L:	linux-arm-msm@vger.kernel.org
+S:	Maintained
+T:	git git://linuxtv.org/media_tree.git
+F:	Documentation/devicetree/bindings/media/qcom,*-iris.yaml
+F:	drivers/media/platform/qcom/iris/
+
 QUALCOMM WCN36XX WIRELESS DRIVER
 M:	Loic Poulain <loic.poulain@linaro.org>
 L:	wcn36xx@lists.infradead.org
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
  2023-07-28 13:23 ` [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:45   ` Konrad Dybcio
                     ` (4 more replies)
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
                   ` (33 subsequent siblings)
  35 siblings, 5 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements the platform driver methods, file
operations and v4l2 registration.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660 +++++++++++++++++++++
 1 file changed, 660 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c

diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
new file mode 100644
index 0000000..43439cb
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/stringify.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_state.h"
+#include "venus_hfi.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_core *g_core;
+
+static inline bool is_video_device(struct device *dev)
+{
+	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
+}
+
+static inline bool is_video_context_bank_device(struct device *dev)
+{
+	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
+}
+
+static int msm_vidc_init_resources(struct msm_vidc_core *core)
+{
+	struct msm_vidc_resource *res = NULL;
+	int rc = 0;
+
+	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
+	if (!res) {
+		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
+		return -ENOMEM;
+	}
+	core->resource = res;
+
+	rc = call_res_op(core, init, core);
+	if (rc) {
+		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id msm_vidc_dt_match[] = {
+	{.compatible = "qcom,sm8550-vidc"},
+	{.compatible = "qcom,vidc,cb-ns"},
+	MSM_VIDC_EMPTY_BRACE
+};
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static void msm_vidc_release_video_device(struct video_device *vdev)
+{
+	d_vpr_e("%s: video device released\n", __func__);
+}
+
+static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
+					     enum msm_vidc_domain_type type)
+{
+	int index;
+
+	if (type == MSM_VIDC_DECODER)
+		index = 0;
+	else if (type == MSM_VIDC_ENCODER)
+		index = 1;
+	else
+		return;
+
+	v4l2_m2m_release(core->vdev[index].m2m_dev);
+
+	video_set_drvdata(&core->vdev[index].vdev, NULL);
+	video_unregister_device(&core->vdev[index].vdev);
+}
+
+static int msm_vidc_register_video_device(struct msm_vidc_core *core,
+					  enum msm_vidc_domain_type type, int nr)
+{
+	int rc = 0;
+	int index;
+
+	d_vpr_h("%s: domain %d\n", __func__, type);
+
+	if (type == MSM_VIDC_DECODER)
+		index = 0;
+	else if (type == MSM_VIDC_ENCODER)
+		index = 1;
+	else
+		return -EINVAL;
+
+	core->vdev[index].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[index].vdev.fops = core->v4l2_file_ops;
+	if (type == MSM_VIDC_DECODER)
+		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
+	else
+		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
+	core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
+	core->vdev[index].type = type;
+	core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
+	core->vdev[index].vdev.device_caps = core->capabilities[DEVICE_CAPS].value;
+	rc = video_register_device(&core->vdev[index].vdev,
+				   VFL_TYPE_VIDEO, nr);
+	if (rc) {
+		d_vpr_e("Failed to register the video device\n");
+		return rc;
+	}
+	video_set_drvdata(&core->vdev[index].vdev, core);
+
+	core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
+	if (IS_ERR(core->vdev[index].m2m_dev)) {
+		d_vpr_e("Failed to initialize V4L2 M2M device\n");
+		rc = PTR_ERR(core->vdev[index].m2m_dev);
+		goto m2m_init_failed;
+	}
+
+	return 0;
+
+m2m_init_failed:
+	video_unregister_device(&core->vdev[index].vdev);
+	return rc;
+}
+
+static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_destroy(&core->lock);
+	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
+
+	if (core->batch_workq)
+		destroy_workqueue(core->batch_workq);
+
+	if (core->pm_workq)
+		destroy_workqueue(core->pm_workq);
+
+	core->batch_workq = NULL;
+	core->pm_workq = NULL;
+
+	return rc;
+}
+
+static int msm_vidc_initialize_core(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
+
+	core->pm_workq = create_singlethread_workqueue("pm_workq");
+	if (!core->pm_workq) {
+		d_vpr_e("%s: create pm workq failed\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	core->batch_workq = create_singlethread_workqueue("batch_workq");
+	if (!core->batch_workq) {
+		d_vpr_e("%s: create batch workq failed\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
+	core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
+	if (!core->packet) {
+		d_vpr_e("%s: failed to alloc core packet\n", __func__);
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	core->response_packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
+	if (!core->packet) {
+		d_vpr_e("%s: failed to alloc core response packet\n", __func__);
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	mutex_init(&core->lock);
+	INIT_LIST_HEAD(&core->instances);
+	INIT_LIST_HEAD(&core->dangling_instances);
+
+	INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
+	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
+
+	return 0;
+exit:
+	if (core->batch_workq)
+		destroy_workqueue(core->batch_workq);
+	if (core->pm_workq)
+		destroy_workqueue(core->pm_workq);
+	core->batch_workq = NULL;
+	core->pm_workq = NULL;
+
+	return rc;
+}
+
+static void msm_vidc_devm_deinit_core(void *res)
+{
+	struct msm_vidc_core *core = res;
+
+	msm_vidc_deinitialize_core(core);
+}
+
+static int msm_vidc_devm_init_core(struct device *dev, struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (!dev || !core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_initialize_core(core);
+	if (rc) {
+		d_vpr_e("%s: init failed with %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void *)core);
+	if (rc)
+		return -EINVAL;
+
+	return rc;
+}
+
+static void msm_vidc_devm_debugfs_put(void *res)
+{
+	struct dentry *parent = res;
+
+	debugfs_remove_recursive(parent);
+}
+
+static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev)
+{
+	struct dentry *parent = NULL;
+	int rc = 0;
+
+	if (!dev) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return NULL;
+	}
+
+	parent = msm_vidc_debugfs_init_drv();
+	if (!parent)
+		return NULL;
+
+	rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void *)parent);
+	if (rc)
+		return NULL;
+
+	return parent;
+}
+
+static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
+				       struct device *dev)
+{
+	struct context_bank_info *cb = NULL;
+	int rc = 0;
+
+	cb = msm_vidc_get_context_bank_for_device(core, dev);
+	if (!cb) {
+		d_vpr_e("%s: Failed to get context bank device for %s\n",
+			__func__, dev_name(dev));
+		return -EIO;
+	}
+
+	/* populate dev & domain field */
+	cb->dev = dev;
+	cb->domain = iommu_get_domain_for_dev(cb->dev);
+	if (!cb->domain) {
+		d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__, dev_name(dev));
+		return -EIO;
+	}
+
+	if (cb->dma_mask) {
+		rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask);
+		if (rc) {
+			d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__);
+			return rc;
+		}
+	}
+
+	/*
+	 * configure device segment size and segment boundary to ensure
+	 * iommu mapping returns one mapping (which is required for partial
+	 * cache operations)
+	 */
+	if (!dev->dma_parms)
+		dev->dma_parms =
+			devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+	dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
+	dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
+
+	iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler, (void *)core);
+
+	d_vpr_h("%s: name %s addr start %x size %x secure %d\n",
+		__func__, cb->name, cb->addr_range.start,
+		cb->addr_range.size, cb->secure);
+	d_vpr_h("%s: dma_coherant %d region %d dev_name %s domain %pK dma_mask %llu\n",
+		__func__, cb->dma_coherant, cb->region, dev_name(cb->dev),
+		cb->domain, cb->dma_mask);
+
+	return rc;
+}
+
+static int msm_vidc_remove_video_device(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core;
+
+	if (!pdev) {
+		d_vpr_e("%s: invalid input %pK", __func__, pdev);
+		return -EINVAL;
+	}
+
+	core = dev_get_drvdata(&pdev->dev);
+	if (!core) {
+		d_vpr_e("%s: invalid core\n", __func__);
+		return -EINVAL;
+	}
+
+	msm_vidc_core_deinit(core, true);
+	venus_hfi_queue_deinit(core);
+
+	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
+	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
+
+	v4l2_device_unregister(&core->v4l2_dev);
+
+	d_vpr_h("depopulating sub devices\n");
+	/*
+	 * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx
+	 * When msm_vidc_remove is called for each sub-device, destroy
+	 * context-bank mappings.
+	 */
+	of_platform_depopulate(&pdev->dev);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+	g_core = NULL;
+	d_vpr_h("%s(): succssful\n", __func__);
+
+	return 0;
+}
+
+static int msm_vidc_remove_context_bank(struct platform_device *pdev)
+{
+	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
+
+	return 0;
+}
+
+static int msm_vidc_remove(struct platform_device *pdev)
+{
+	/*
+	 * Sub devices remove will be triggered by of_platform_depopulate()
+	 * after core_deinit(). It return immediately after completing
+	 * sub-device remove.
+	 */
+	if (is_video_device(&pdev->dev))
+		return msm_vidc_remove_video_device(pdev);
+	else if (is_video_context_bank_device(&pdev->dev))
+		return msm_vidc_remove_context_bank(pdev);
+
+	/* How did we end up here? */
+	WARN_ON(1);
+	return -EINVAL;
+}
+
+static int msm_vidc_probe_video_device(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = NULL;
+	int nr = BASE_DEVICE_NUMBER;
+
+	d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
+
+	core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL);
+	if (!core) {
+		d_vpr_e("%s: failed to alloc memory for core\n", __func__);
+		return -ENOMEM;
+	}
+	g_core = core;
+
+	core->pdev = pdev;
+	dev_set_drvdata(&pdev->dev, core);
+
+	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
+	if (!core->debugfs_parent)
+		d_vpr_h("Failed to create debugfs for msm_vidc\n");
+
+	rc = msm_vidc_devm_init_core(&pdev->dev, core);
+	if (rc) {
+		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
+		goto init_core_failed;
+	}
+
+	rc = msm_vidc_init_platform(core);
+	if (rc) {
+		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto init_plat_failed;
+	}
+
+	rc = msm_vidc_init_resources(core);
+	if (rc) {
+		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
+		goto init_res_failed;
+	}
+
+	rc = msm_vidc_init_core_caps(core);
+	if (rc) {
+		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
+		goto init_res_failed;
+	}
+
+	rc = msm_vidc_init_instance_caps(core);
+	if (rc) {
+		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
+		goto init_inst_caps_fail;
+	}
+
+	core->debugfs_root = msm_vidc_debugfs_init_core(core);
+	if (!core->debugfs_root)
+		d_vpr_h("Failed to init debugfs core\n");
+
+	d_vpr_h("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.
+	 */
+	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
+				  &pdev->dev);
+	if (rc) {
+		d_vpr_e("Failed to trigger probe for sub-devices\n");
+		goto sub_dev_failed;
+	}
+
+	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+	if (rc) {
+		d_vpr_e("Failed to register v4l2 device\n");
+		goto v4l2_reg_failed;
+	}
+
+	/* setup the decoder device */
+	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
+	if (rc) {
+		d_vpr_e("Failed to register video decoder\n");
+		goto dec_reg_failed;
+	}
+
+	/* setup the encoder device */
+	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
+	if (rc) {
+		d_vpr_e("Failed to register video encoder\n");
+		goto enc_reg_failed;
+	}
+
+	rc = venus_hfi_queue_init(core);
+	if (rc) {
+		d_vpr_e("%s: interface queues init failed\n", __func__);
+		goto queues_init_failed;
+	}
+
+	rc = msm_vidc_core_init(core);
+	if (rc) {
+		d_vpr_e("%s: sys init failed\n", __func__);
+		goto core_init_failed;
+	}
+
+	d_vpr_h("%s(): succssful\n", __func__);
+
+	return rc;
+
+core_init_failed:
+	venus_hfi_queue_deinit(core);
+queues_init_failed:
+	of_platform_depopulate(&pdev->dev);
+sub_dev_failed:
+	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
+enc_reg_failed:
+	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
+dec_reg_failed:
+	v4l2_device_unregister(&core->v4l2_dev);
+v4l2_reg_failed:
+init_inst_caps_fail:
+init_res_failed:
+init_plat_failed:
+init_core_failed:
+	dev_set_drvdata(&pdev->dev, NULL);
+	g_core = NULL;
+
+	return rc;
+}
+
+static int msm_vidc_probe_context_bank(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core = NULL;
+	int rc = 0;
+
+	if (!pdev) {
+		d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
+		return -EINVAL;
+	} else if (!pdev->dev.parent) {
+		d_vpr_e("%s: Failed to find a parent for %s\n",
+			__func__, dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
+
+	core = dev_get_drvdata(pdev->dev.parent);
+	if (!core) {
+		d_vpr_e("%s: core not found in device %s",
+			__func__, dev_name(pdev->dev.parent));
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_setup_context_bank(core, &pdev->dev);
+	if (rc) {
+		d_vpr_e("%s: Failed to probe context bank %s\n",
+			__func__, dev_name(&pdev->dev));
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_probe(struct platform_device *pdev)
+{
+	if (!pdev) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * 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 (is_video_device(&pdev->dev))
+		return msm_vidc_probe_video_device(pdev);
+	else if (is_video_context_bank_device(&pdev->dev))
+		return msm_vidc_probe_context_bank(pdev);
+
+	/* How did we end up here? */
+	WARN_ON(1);
+	return -EINVAL;
+}
+
+static int msm_vidc_pm_suspend(struct device *dev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+
+	/*
+	 * Bail out if
+	 * - driver possibly not probed yet
+	 * - not the main device. We don't support power management on
+	 *   subdevices (e.g. context banks)
+	 */
+	if (!dev || !dev->driver || !is_video_device(dev))
+		return 0;
+
+	core = dev_get_drvdata(dev);
+	if (!core) {
+		d_vpr_e("%s: invalid core\n", __func__);
+		return -EINVAL;
+	}
+
+	core_lock(core, __func__);
+	allow = msm_vidc_allow_pm_suspend(core);
+
+	if (allow == MSM_VIDC_IGNORE) {
+		d_vpr_h("%s: pm already suspended\n", __func__);
+		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
+		rc = 0;
+		goto unlock;
+	} else if (allow != MSM_VIDC_ALLOW) {
+		d_vpr_h("%s: pm suspend not allowed\n", __func__);
+		rc = 0;
+		goto unlock;
+	}
+
+	rc = msm_vidc_suspend(core);
+	if (rc == -EOPNOTSUPP)
+		rc = 0;
+	else if (rc)
+		d_vpr_e("Failed to suspend: %d\n", rc);
+	else
+		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+static int msm_vidc_pm_resume(struct device *dev)
+{
+	struct msm_vidc_core *core;
+
+	/*
+	 * Bail out if
+	 * - driver possibly not probed yet
+	 * - not the main device. We don't support power management on
+	 *   subdevices (e.g. context banks)
+	 */
+	if (!dev || !dev->driver || !is_video_device(dev))
+		return 0;
+
+	core = dev_get_drvdata(dev);
+	if (!core) {
+		d_vpr_e("%s: invalid core\n", __func__);
+		return -EINVAL;
+	}
+
+	/* remove PM suspend from core sub_state */
+	core_lock(core, __func__);
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
+	core_unlock(core, __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)
+};
+
+struct platform_driver msm_vidc_driver = {
+	.probe = msm_vidc_probe,
+	.remove = msm_vidc_remove,
+	.driver = {
+		.name = "msm_vidc_v4l2",
+		.of_match_table = msm_vidc_dt_match,
+		.pm = &msm_vidc_pm_ops,
+	},
+};
+
+module_platform_driver(msm_vidc_driver);
+MODULE_LICENSE("GPL");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
  2023-07-28 13:23 ` [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver Vikash Garodia
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:34   ` Dmitry Baryshkov
                     ` (3 more replies)
  2023-07-28 13:23 ` [PATCH 04/33] iris: add vidc " Vikash Garodia
                   ` (32 subsequent siblings)
  35 siblings, 4 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

Here is the implementation of v4l2 wrapper functions for all
v4l2 IOCTLs.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
 2 files changed, 1030 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
new file mode 100644
index 0000000..3766c9d
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_V4L2_H_
+#define _MSM_VIDC_V4L2_H_
+
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+int msm_v4l2_open(struct file *filp);
+int msm_v4l2_close(struct file *filp);
+int msm_v4l2_querycap(struct file *filp, void *fh,
+		      struct v4l2_capability *cap);
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+		      struct v4l2_fmtdesc *f);
+int msm_v4l2_try_fmt(struct file *file, void *fh,
+		     struct v4l2_format *f);
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+		   struct v4l2_format *f);
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+		   struct v4l2_format *f);
+int msm_v4l2_s_selection(struct file *file, void *fh,
+			 struct v4l2_selection *s);
+int msm_v4l2_g_selection(struct file *file, void *fh,
+			 struct v4l2_selection *s);
+int msm_v4l2_s_parm(struct file *file, void *fh,
+		    struct v4l2_streamparm *a);
+int msm_v4l2_g_parm(struct file *file, void *fh,
+		    struct v4l2_streamparm *a);
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+		     struct v4l2_requestbuffers *b);
+int msm_v4l2_querybuf(struct file *file, void *fh,
+		      struct v4l2_buffer *b);
+int msm_v4l2_create_bufs(struct file *filp, void *fh,
+			 struct v4l2_create_buffers *b);
+int msm_v4l2_prepare_buf(struct file *filp, void *fh,
+			 struct v4l2_buffer *b);
+int msm_v4l2_qbuf(struct file *file, void *fh,
+		  struct v4l2_buffer *b);
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+		   struct v4l2_buffer *b);
+int msm_v4l2_streamon(struct file *file, void *fh,
+		      enum v4l2_buf_type i);
+int msm_v4l2_streamoff(struct file *file, void *fh,
+		       enum v4l2_buf_type i);
+int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+			     const struct v4l2_event_subscription *sub);
+int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+			       const struct v4l2_event_subscription *sub);
+int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
+			     struct v4l2_decoder_cmd *enc);
+int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+			 struct v4l2_decoder_cmd *dec);
+int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
+			     struct v4l2_encoder_cmd *enc);
+int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+			 struct v4l2_encoder_cmd *enc);
+int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+			     struct v4l2_frmsizeenum *fsize);
+int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
+				 struct v4l2_frmivalenum *fival);
+int msm_v4l2_queryctrl(struct file *file, void *fh,
+		       struct v4l2_queryctrl *ctrl);
+int msm_v4l2_querymenu(struct file *file, void *fh,
+		       struct v4l2_querymenu *qmenu);
+unsigned int msm_v4l2_poll(struct file *filp,
+			   struct poll_table_struct *pt);
+void msm_v4l2_m2m_device_run(void *priv);
+void msm_v4l2_m2m_job_abort(void *priv);
+
+#endif // _MSM_VIDC_V4L2_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
new file mode 100644
index 0000000..6dfb18b
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
@@ -0,0 +1,953 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_v4l2.h"
+
+static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+	if (!filp || !filp->private_data)
+		return NULL;
+	return container_of(filp->private_data,
+					struct msm_vidc_inst, fh);
+}
+
+unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
+{
+	int poll = 0;
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return POLLERR;
+	}
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		poll = POLLERR;
+		goto exit;
+	}
+
+	poll = msm_vidc_poll((void *)inst, filp, pt);
+	if (poll)
+		goto exit;
+
+exit:
+	put_inst(inst);
+	return poll;
+}
+
+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 *inst;
+
+	inst = msm_vidc_open(core, vid_dev->type);
+	if (!inst) {
+		d_vpr_e("Failed to create instance, type = %d\n",
+			vid_dev->type);
+		return -ENOMEM;
+	}
+	filp->private_data = &inst->fh;
+	return 0;
+}
+
+int msm_v4l2_close(struct file *filp)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+
+	inst = get_vidc_inst(filp, NULL);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_close(inst);
+	filp->private_data = NULL;
+	return rc;
+}
+
+int msm_v4l2_querycap(struct file *filp, void *fh,
+		      struct v4l2_capability *cap)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !cap) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_querycap((void *)inst, cap);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_enum_fmt(struct file *filp, void *fh,
+		      struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !f) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_enum_fmt((void *)inst, f);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !f) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_s_fmt(struct file *filp, void *fh,
+		   struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !f) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_g_fmt(struct file *filp, void *fh,
+		   struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !f) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_g_fmt((void *)inst, f);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_s_selection(struct file *filp, void *fh,
+			 struct v4l2_selection *s)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_s_selection((void *)inst, s);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_g_selection(struct file *filp, void *fh,
+			 struct v4l2_selection *s)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_g_selection((void *)inst, s);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_s_parm(struct file *filp, void *fh,
+		    struct v4l2_streamparm *a)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !a) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_s_param((void *)inst, a);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_g_parm(struct file *filp, void *fh,
+		    struct v4l2_streamparm *a)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !a) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_g_param((void *)inst, a);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_reqbufs(struct file *filp, void *fh,
+		     struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_querybuf(struct file *filp, void *fh,
+		      struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_querybuf((void *)inst, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_create_bufs(struct file *filp, void *fh,
+			 struct v4l2_create_buffers *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_create_bufs((void *)inst, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_prepare_buf(struct file *filp, void *fh,
+			 struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	struct video_device *vdev = video_devdata(filp);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_qbuf(struct file *filp, void *fh,
+		  struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	struct video_device *vdev = video_devdata(filp);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
+	if (rc)
+		goto exit;
+
+exit:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_dqbuf(struct file *filp, void *fh,
+		   struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !b) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = msm_vidc_dqbuf(inst, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_streamon(struct file *filp, void *fh,
+		      enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto exit;
+	}
+
+	rc = msm_vidc_streamon((void *)inst, i);
+	if (rc)
+		goto exit;
+
+exit:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_streamoff(struct file *filp, void *fh,
+		       enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = msm_vidc_streamoff((void *)inst, i);
+	if (rc)
+		i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
+
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+			     const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	inst = container_of(fh, struct msm_vidc_inst, fh);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !sub) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_subscribe_event((void *)inst, sub);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+			       const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	inst = container_of(fh, struct msm_vidc_inst, fh);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !sub) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = msm_vidc_unsubscribe_event((void *)inst, sub);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh,
+			     struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !dec) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
+			 struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	enum msm_vidc_event event;
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	if (!dec) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	if (dec->cmd != V4L2_DEC_CMD_START &&
+	    dec->cmd != V4L2_DEC_CMD_STOP) {
+		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
+	rc = inst->event_handle(inst, event, NULL);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh,
+			     struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !enc) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
+			 struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	enum msm_vidc_event event;
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	if (!enc) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	if (enc->cmd != V4L2_ENC_CMD_START &&
+	    enc->cmd != V4L2_ENC_CMD_STOP) {
+		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
+	rc = inst->event_handle(inst, event, NULL);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_enum_framesizes(struct file *filp, void *fh,
+			     struct v4l2_frmsizeenum *fsize)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !fsize) {
+		d_vpr_e("%s: invalid params: %pK %pK\n",
+			__func__, inst, fsize);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_enum_framesizes((void *)inst, fsize);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_enum_frameintervals(struct file *filp, void *fh,
+				 struct v4l2_frmivalenum *fival)
+
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !fival) {
+		d_vpr_e("%s: invalid params: %pK %pK\n",
+			__func__, inst, fival);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_enum_frameintervals((void *)inst, fival);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_queryctrl(struct file *filp, void *fh,
+		       struct v4l2_queryctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !ctrl) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_query_ctrl((void *)inst, ctrl);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_v4l2_querymenu(struct file *filp, void *fh,
+		       struct v4l2_querymenu *qmenu)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !qmenu) {
+		d_vpr_e("%s: invalid params %pK %pK\n",
+			__func__, inst, qmenu);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+	rc = msm_vidc_query_menu((void *)inst, qmenu);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+void msm_v4l2_m2m_device_run(void *priv)
+{
+	d_vpr_l("%s(): device_run\n", __func__);
+}
+
+void msm_v4l2_m2m_job_abort(void *priv)
+{
+	struct msm_vidc_inst *inst = priv;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+	i_vpr_h(inst, "%s: m2m job aborted\n", __func__);
+	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 04/33] iris: add vidc wrapper file
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (2 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 05/33] iris: vidc: add vb2 ops Vikash Garodia
                   ` (31 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements vidc wrapper functions for all v4l2 IOCTLs.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/msm_vidc.h   |  60 ++
 .../media/platform/qcom/iris/vidc/src/msm_vidc.c   | 841 +++++++++++++++++++++
 2 files changed, 901 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
new file mode 100644
index 0000000..6cd5fad
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/videodev2.h>
+#include <media/media-device.h>
+
+struct msm_vidc_core;
+struct msm_vidc_inst;
+
+union msm_v4l2_cmd {
+	struct v4l2_decoder_cmd dec;
+	struct v4l2_encoder_cmd enc;
+};
+
+void *msm_vidc_open(struct msm_vidc_core *core, u32 session_type);
+int msm_vidc_close(struct msm_vidc_inst *inst);
+int msm_vidc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);
+int msm_vidc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vidc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vidc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vidc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_vidc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_vidc_s_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *sp);
+int msm_vidc_g_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *sp);
+int msm_vidc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b);
+int msm_vidc_querybuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vidc_create_bufs(struct msm_vidc_inst *inst, struct v4l2_create_buffers *b);
+int msm_vidc_prepare_buf(struct msm_vidc_inst *inst, struct media_device *mdev,
+			 struct v4l2_buffer *b);
+int msm_vidc_release_buffer(struct msm_vidc_inst *inst, int buffer_type,
+			    unsigned int buffer_index);
+int msm_vidc_qbuf(struct msm_vidc_inst *inst, struct media_device *mdev,
+		  struct v4l2_buffer *b);
+int msm_vidc_dqbuf(struct msm_vidc_inst *inste, struct v4l2_buffer *b);
+int msm_vidc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vidc_query_ctrl(struct msm_vidc_inst *inst, struct v4l2_queryctrl *ctrl);
+int msm_vidc_query_menu(struct msm_vidc_inst *inst, struct v4l2_querymenu *qmenu);
+int msm_vidc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vidc_try_cmd(struct msm_vidc_inst *inst, union msm_v4l2_cmd *cmd);
+int msm_vidc_start_cmd(struct msm_vidc_inst *inst);
+int msm_vidc_stop_cmd(struct msm_vidc_inst *inst);
+int msm_vidc_poll(struct msm_vidc_inst *inst, struct file *filp,
+		  struct poll_table_struct *pt);
+int msm_vidc_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub);
+int msm_vidc_unsubscribe_event(struct msm_vidc_inst *inst,
+			       const struct v4l2_event_subscription *sub);
+int msm_vidc_dqevent(struct msm_vidc_inst *inst, struct v4l2_event *event);
+int msm_vidc_g_crop(struct msm_vidc_inst *inst, struct v4l2_crop *a);
+int msm_vidc_enum_framesizes(struct msm_vidc_inst *inst, struct v4l2_frmsizeenum *fsize);
+int msm_vidc_enum_frameintervals(struct msm_vidc_inst *inst, struct v4l2_frmivalenum *fival);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
new file mode 100644
index 0000000..c9848c7
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
@@ -0,0 +1,841 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/hash.h>
+#include <linux/types.h>
+
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_power.h"
+#include "msm_vidc_v4l2.h"
+#include "msm_vidc_vb2.h"
+#include "venus_hfi_response.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_BUS_NAME "platform:msm_vidc_bus"
+
+static inline bool valid_v4l2_buffer(struct v4l2_buffer *b,
+				     struct msm_vidc_inst *inst)
+{
+	if (b->type == INPUT_MPLANE || b->type == OUTPUT_MPLANE)
+		return b->length > 0;
+
+	return false;
+}
+
+static int get_poll_flags(struct msm_vidc_inst *inst, u32 port)
+{
+	int poll = 0;
+	struct vb2_queue *q = NULL;
+	struct vb2_buffer *vb = NULL;
+	unsigned long flags = 0;
+
+	if (port >= MAX_PORT) {
+		d_vpr_e("%s: invalid params, inst %pK, port %d\n",
+			__func__, inst, port);
+		return poll;
+	}
+	q = inst->bufq[port].vb2q;
+
+	spin_lock_irqsave(&q->done_lock, flags);
+	if (!list_empty(&q->done_list))
+		vb = list_first_entry(&q->done_list, struct vb2_buffer,
+				      done_entry);
+	if (vb && (vb->state == VB2_BUF_STATE_DONE ||
+		   vb->state == VB2_BUF_STATE_ERROR)) {
+		if (port == OUTPUT_PORT)
+			poll |= POLLIN | POLLRDNORM;
+		else if (port == INPUT_PORT)
+			poll |= POLLOUT | POLLWRNORM;
+	}
+	spin_unlock_irqrestore(&q->done_lock, flags);
+
+	return poll;
+}
+
+int msm_vidc_poll(struct msm_vidc_inst *inst, struct file *filp,
+		  struct poll_table_struct *wait)
+{
+	int poll = 0;
+
+	poll_wait(filp, &inst->fh.wait, wait);
+	poll_wait(filp, &inst->bufq[INPUT_PORT].vb2q->done_wq, wait);
+	poll_wait(filp, &inst->bufq[OUTPUT_PORT].vb2q->done_wq, wait);
+
+	if (v4l2_event_pending(&inst->fh))
+		poll |= POLLPRI;
+
+	poll |= get_poll_flags(inst, INPUT_PORT);
+	poll |= get_poll_flags(inst, OUTPUT_PORT);
+
+	return poll;
+}
+
+int msm_vidc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	strscpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strscpy(cap->bus_info, MSM_VIDC_BUS_NAME, sizeof(cap->bus_info));
+
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+
+	if (is_decode_session(inst))
+		strscpy(cap->card, "msm_vidc_decoder", sizeof(cap->card));
+	else if (is_encode_session(inst))
+		strscpy(cap->card, "msm_vidc_encoder", sizeof(cap->card));
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+int msm_vidc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	if (is_decode_session(inst))
+		return msm_vdec_enum_fmt(inst, f);
+	if (is_encode_session(inst))
+		return msm_venc_enum_fmt(inst, f);
+
+	return -EINVAL;
+}
+
+int msm_vidc_query_ctrl(struct msm_vidc_inst *inst, struct v4l2_queryctrl *q_ctrl)
+{
+	int rc = 0;
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&inst->ctrl_handler, q_ctrl->id);
+	if (!ctrl) {
+		i_vpr_e(inst, "%s: get_ctrl failed for id %d\n",
+			__func__, q_ctrl->id);
+		return -EINVAL;
+	}
+	q_ctrl->minimum = ctrl->minimum;
+	q_ctrl->maximum = ctrl->maximum;
+	q_ctrl->default_value = ctrl->default_value;
+	q_ctrl->flags = 0;
+	q_ctrl->step = ctrl->step;
+	i_vpr_h(inst,
+		"query ctrl: %s: min %d, max %d, default %d step %d flags %#x\n",
+		ctrl->name, q_ctrl->minimum, q_ctrl->maximum,
+		q_ctrl->default_value, q_ctrl->step, q_ctrl->flags);
+	return rc;
+}
+
+int msm_vidc_query_menu(struct msm_vidc_inst *inst, struct v4l2_querymenu *qmenu)
+{
+	int rc = 0;
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&inst->ctrl_handler, qmenu->id);
+	if (!ctrl) {
+		i_vpr_e(inst, "%s: get_ctrl failed for id %d\n",
+			__func__, qmenu->id);
+		return -EINVAL;
+	}
+	if (ctrl->type != V4L2_CTRL_TYPE_MENU) {
+		i_vpr_e(inst, "%s: ctrl: %s: type (%d) is not MENU type\n",
+			__func__, ctrl->name, ctrl->type);
+		return -EINVAL;
+	}
+	if (qmenu->index < ctrl->minimum || qmenu->index > ctrl->maximum)
+		return -EINVAL;
+
+	if (ctrl->menu_skip_mask & (1 << qmenu->index))
+		rc = -EINVAL;
+
+	i_vpr_h(inst,
+		"%s: ctrl: %s: min %lld, max %lld, menu_skip_mask %lld, qmenu: id %u, index %d, %s\n",
+		__func__, ctrl->name, ctrl->minimum, ctrl->maximum,
+		ctrl->menu_skip_mask, qmenu->id, qmenu->index,
+		rc ? "not supported" : "supported");
+	return rc;
+}
+
+int msm_vidc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_try_fmt(inst, f);
+	if (is_encode_session(inst))
+		rc = msm_venc_try_fmt(inst, f);
+
+	if (rc)
+		i_vpr_e(inst, "%s: try_fmt(%d) failed %d\n",
+			__func__, f->type, rc);
+	return rc;
+}
+
+int msm_vidc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_s_fmt(inst, f);
+	if (is_encode_session(inst))
+		rc = msm_venc_s_fmt(inst, f);
+
+	if (rc)
+		i_vpr_e(inst, "%s: s_fmt(%d) failed %d\n",
+			__func__, f->type, rc);
+	return rc;
+}
+
+int msm_vidc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_g_fmt(inst, f);
+	if (is_encode_session(inst))
+		rc = msm_venc_g_fmt(inst, f);
+	if (rc)
+		return rc;
+
+	i_vpr_h(inst, "%s: type %s format %s width %d height %d size %d\n",
+		__func__, v4l2_type_name(f->type),
+		v4l2_pixelfmt_name(inst, f->fmt.pix_mp.pixelformat),
+		f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+		f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+	return 0;
+}
+
+int msm_vidc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	int rc = 0;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_s_selection(inst, s);
+	if (is_encode_session(inst))
+		rc = msm_venc_s_selection(inst, s);
+
+	return rc;
+}
+
+int msm_vidc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	int rc = 0;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_g_selection(inst, s);
+	if (is_encode_session(inst))
+		rc = msm_venc_g_selection(inst, s);
+
+	return rc;
+}
+
+int msm_vidc_s_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *param)
+{
+	int rc = 0;
+
+	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    param->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	if (is_encode_session(inst)) {
+		rc = msm_venc_s_param(inst, param);
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %#x\n",
+			__func__, inst->domain);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int msm_vidc_g_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *param)
+{
+	int rc = 0;
+
+	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    param->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	if (is_encode_session(inst)) {
+		rc = msm_venc_g_param(inst, param);
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %#x\n",
+			__func__, inst->domain);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int msm_vidc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, b->type, __func__);
+	if (port < 0) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_reqbufs(inst->bufq[port].vb2q, b);
+	if (rc) {
+		i_vpr_e(inst, "%s: vb2_reqbufs(%d) failed, %d\n",
+			__func__, b->type, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_querybuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, b->type, __func__);
+	if (port < 0) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_querybuf(inst->bufq[port].vb2q, b);
+	if (rc) {
+		i_vpr_e(inst, "%s: vb2_querybuf(%d) failed, %d\n",
+			__func__, b->type, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_create_bufs(struct msm_vidc_inst *inst, struct v4l2_create_buffers *b)
+{
+	int rc = 0;
+	int port;
+	struct v4l2_format *f;
+
+	f = &b->format;
+	port = v4l2_type_to_driver_port(inst, f->type, __func__);
+	if (port < 0) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_create_bufs(inst->bufq[port].vb2q, b);
+	if (rc) {
+		i_vpr_e(inst, "%s: vb2_create_bufs(%d) failed, %d\n",
+			__func__, f->type, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_prepare_buf(struct msm_vidc_inst *inst, struct media_device *mdev,
+			 struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+
+	if (!valid_v4l2_buffer(b, inst)) {
+		d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_vidc_get_vb2q(inst, b->type, __func__);
+	if (!q) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_prepare_buf(q, mdev, b);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed with %d\n", __func__, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_qbuf(struct msm_vidc_inst *inst, struct media_device *mdev,
+		  struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+
+	if (!valid_v4l2_buffer(b, inst)) {
+		d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_vidc_get_vb2q(inst, b->type, __func__);
+	if (!q) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_qbuf(q, mdev, b);
+	if (rc)
+		i_vpr_e(inst, "%s: failed with %d\n", __func__, rc);
+
+exit:
+	return rc;
+}
+
+int msm_vidc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+
+	if (!valid_v4l2_buffer(b, inst)) {
+		d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_vidc_get_vb2q(inst, b->type, __func__);
+	if (!q) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_dqbuf(q, b, true);
+	if (rc == -EAGAIN) {
+		goto exit;
+	} else if (rc) {
+		i_vpr_l(inst, "%s: failed with %d\n", __func__, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, type, __func__);
+	if (port < 0) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_streamon(inst->bufq[port].vb2q, type);
+	if (rc) {
+		i_vpr_e(inst, "%s: vb2_streamon(%d) failed, %d\n",
+			__func__, type, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_streamon);
+
+int msm_vidc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, type, __func__);
+	if (port < 0) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_streamoff(inst->bufq[port].vb2q, type);
+	if (rc) {
+		i_vpr_e(inst, "%s: vb2_streamoff(%d) failed, %d\n",
+			__func__, type, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_try_cmd(struct msm_vidc_inst *inst, union msm_v4l2_cmd *cmd)
+{
+	int rc = 0;
+	struct v4l2_decoder_cmd *dec = NULL;
+	struct v4l2_encoder_cmd *enc = NULL;
+
+	if (is_decode_session(inst)) {
+		dec = (struct v4l2_decoder_cmd *)cmd;
+		i_vpr_h(inst, "%s: cmd %d\n", __func__, dec->cmd);
+		if (dec->cmd != V4L2_DEC_CMD_STOP && dec->cmd != V4L2_DEC_CMD_START)
+			return -EINVAL;
+		dec->flags = 0;
+		if (dec->cmd == V4L2_DEC_CMD_STOP) {
+			dec->stop.pts = 0;
+		} else if (dec->cmd == V4L2_DEC_CMD_START) {
+			dec->start.speed = 0;
+			dec->start.format = V4L2_DEC_START_FMT_NONE;
+		}
+	} else if (is_encode_session(inst)) {
+		enc = (struct v4l2_encoder_cmd *)cmd;
+		i_vpr_h(inst, "%s: cmd %d\n", __func__, enc->cmd);
+		if (enc->cmd != V4L2_ENC_CMD_STOP && enc->cmd != V4L2_ENC_CMD_START)
+			return -EINVAL;
+		enc->flags = 0;
+	}
+
+	return rc;
+}
+
+int msm_vidc_start_cmd(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst)) {
+		rc = msm_vdec_start_cmd(inst);
+		if (rc)
+			return rc;
+	} else if (is_encode_session(inst)) {
+		rc = msm_venc_start_cmd(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_stop_cmd(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst)) {
+		rc = msm_vdec_stop_cmd(inst);
+		if (rc)
+			return rc;
+	} else if (is_encode_session(inst)) {
+		rc = msm_venc_stop_cmd(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_enum_framesizes(struct msm_vidc_inst *inst, struct v4l2_frmsizeenum *fsize)
+{
+	enum msm_vidc_colorformat_type colorfmt;
+	enum msm_vidc_codec_type codec;
+
+	/* only index 0 allowed as per v4l2 spec */
+	if (fsize->index)
+		return -EINVAL;
+
+	/* validate pixel format */
+	codec = v4l2_codec_to_driver(inst, fsize->pixel_format, __func__);
+	if (!codec) {
+		colorfmt = v4l2_colorformat_to_driver(inst, fsize->pixel_format,
+						      __func__);
+		if (colorfmt == MSM_VIDC_FMT_NONE) {
+			i_vpr_e(inst, "%s: unsupported pix fmt %#x\n",
+				__func__, fsize->pixel_format);
+			return -EINVAL;
+		}
+	}
+
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = inst->capabilities[FRAME_WIDTH].min;
+	fsize->stepwise.max_width = inst->capabilities[FRAME_WIDTH].max;
+	fsize->stepwise.step_width =
+		inst->capabilities[FRAME_WIDTH].step_or_mask;
+	fsize->stepwise.min_height = inst->capabilities[FRAME_HEIGHT].min;
+	fsize->stepwise.max_height = inst->capabilities[FRAME_HEIGHT].max;
+	fsize->stepwise.step_height =
+		inst->capabilities[FRAME_HEIGHT].step_or_mask;
+
+	return 0;
+}
+
+int msm_vidc_enum_frameintervals(struct msm_vidc_inst *inst, struct v4l2_frmivalenum *fival)
+{
+	struct msm_vidc_core *core;
+	enum msm_vidc_colorformat_type colorfmt;
+	u32 fps, mbpf;
+
+	if (is_decode_session(inst)) {
+		i_vpr_e(inst, "%s: not supported by decoder\n", __func__);
+		return -ENOTTY;
+	}
+
+	core = inst->core;
+
+	/* only index 0 allowed as per v4l2 spec */
+	if (fival->index)
+		return -EINVAL;
+
+	/* validate pixel format */
+	colorfmt = v4l2_colorformat_to_driver(inst, fival->pixel_format, __func__);
+	if (colorfmt == MSM_VIDC_FMT_NONE) {
+		i_vpr_e(inst, "%s: unsupported pix fmt %#x\n",
+			__func__, fival->pixel_format);
+		return -EINVAL;
+	}
+
+	/* validate resolution */
+	if (fival->width > inst->capabilities[FRAME_WIDTH].max ||
+	    fival->width < inst->capabilities[FRAME_WIDTH].min ||
+	    fival->height > inst->capabilities[FRAME_HEIGHT].max ||
+	    fival->height < inst->capabilities[FRAME_HEIGHT].min) {
+		i_vpr_e(inst, "%s: unsupported resolution %u x %u\n", __func__,
+			fival->width, fival->height);
+		return -EINVAL;
+	}
+
+	/* calculate max supported fps for a given resolution */
+	mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width);
+	fps = core->capabilities[MAX_MBPS].value / mbpf;
+
+	fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+	fival->stepwise.min.numerator = 1;
+	fival->stepwise.min.denominator =
+			min_t(u32, fps, inst->capabilities[FRAME_RATE].max);
+	fival->stepwise.max.numerator = 1;
+	fival->stepwise.max.denominator = 1;
+	fival->stepwise.step.numerator = 1;
+	fival->stepwise.step.denominator = inst->capabilities[FRAME_RATE].max;
+
+	return 0;
+}
+
+int msm_vidc_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	i_vpr_h(inst, "%s: type %d id %d\n", __func__, sub->type, sub->id);
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_subscribe_event(inst, sub);
+	if (is_encode_session(inst))
+		rc = msm_venc_subscribe_event(inst, sub);
+
+	return rc;
+}
+
+int msm_vidc_unsubscribe_event(struct msm_vidc_inst *inst,
+			       const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	i_vpr_h(inst, "%s: type %d id %d\n", __func__, sub->type, sub->id);
+	rc = v4l2_event_unsubscribe(&inst->fh, sub);
+	if (rc)
+		i_vpr_e(inst, "%s: failed, type %d id %d\n",
+			__func__, sub->type, sub->id);
+	return rc;
+}
+
+int msm_vidc_dqevent(struct msm_vidc_inst *inst, struct v4l2_event *event)
+{
+	int rc = 0;
+
+	rc = v4l2_event_dequeue(&inst->fh, event, false);
+	if (rc)
+		i_vpr_e(inst, "%s: fialed\n", __func__);
+	return rc;
+}
+
+void *msm_vidc_open(struct msm_vidc_core *core, u32 session_type)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = NULL;
+	int i = 0;
+
+	d_vpr_h("%s: %s\n", __func__, video_banner);
+
+	if (session_type != MSM_VIDC_DECODER &&
+	    session_type != MSM_VIDC_ENCODER) {
+		d_vpr_e("%s: invalid session_type %d\n",
+			__func__, session_type);
+		return NULL;
+	}
+
+	rc = msm_vidc_core_init(core);
+	if (rc)
+		return NULL;
+
+	rc = msm_vidc_core_init_wait(core);
+	if (rc)
+		return NULL;
+
+	inst = vzalloc(sizeof(*inst));
+	if (!inst) {
+		d_vpr_e("%s: allocation failed\n", __func__);
+		return NULL;
+	}
+
+	inst->core = core;
+	inst->domain = session_type;
+	inst->session_id = hash32_ptr(inst);
+	msm_vidc_update_state(inst, MSM_VIDC_OPEN, __func__);
+	inst->sub_state = MSM_VIDC_SUB_STATE_NONE;
+	strscpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name));
+	inst->active = true;
+	inst->ipsc_properties_set = false;
+	inst->opsc_properties_set = false;
+	inst->caps_list_prepared = false;
+	inst->has_bframe = false;
+	inst->iframe = false;
+	inst->initial_time_us = ktime_get_ns() / 1000;
+	kref_init(&inst->kref);
+	mutex_init(&inst->lock);
+	mutex_init(&inst->ctx_q_lock);
+	mutex_init(&inst->client_lock);
+	msm_vidc_update_debug_str(inst);
+	i_vpr_h(inst, "Opening video instance: %d\n", session_type);
+
+	rc = msm_vidc_add_session(inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to add session\n", __func__);
+		goto fail_add_session;
+	}
+
+	rc = msm_vidc_pools_init(inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to init pool buffers\n", __func__);
+		goto fail_pools_init;
+	}
+	INIT_LIST_HEAD(&inst->caps_list);
+	INIT_LIST_HEAD(&inst->timestamps.list);
+	INIT_LIST_HEAD(&inst->buffers.input.list);
+	INIT_LIST_HEAD(&inst->buffers.output.list);
+	INIT_LIST_HEAD(&inst->buffers.read_only.list);
+	INIT_LIST_HEAD(&inst->buffers.bin.list);
+	INIT_LIST_HEAD(&inst->buffers.arp.list);
+	INIT_LIST_HEAD(&inst->buffers.comv.list);
+	INIT_LIST_HEAD(&inst->buffers.non_comv.list);
+	INIT_LIST_HEAD(&inst->buffers.line.list);
+	INIT_LIST_HEAD(&inst->buffers.dpb.list);
+	INIT_LIST_HEAD(&inst->buffers.persist.list);
+	INIT_LIST_HEAD(&inst->buffers.vpss.list);
+	INIT_LIST_HEAD(&inst->mem_info.bin.list);
+	INIT_LIST_HEAD(&inst->mem_info.arp.list);
+	INIT_LIST_HEAD(&inst->mem_info.comv.list);
+	INIT_LIST_HEAD(&inst->mem_info.non_comv.list);
+	INIT_LIST_HEAD(&inst->mem_info.line.list);
+	INIT_LIST_HEAD(&inst->mem_info.dpb.list);
+	INIT_LIST_HEAD(&inst->mem_info.persist.list);
+	INIT_LIST_HEAD(&inst->mem_info.vpss.list);
+	INIT_LIST_HEAD(&inst->children_list);
+	INIT_LIST_HEAD(&inst->firmware_list);
+	INIT_LIST_HEAD(&inst->enc_input_crs);
+	INIT_LIST_HEAD(&inst->dmabuf_tracker);
+	INIT_LIST_HEAD(&inst->input_timer_list);
+	INIT_LIST_HEAD(&inst->buffer_stats_list);
+	for (i = 0; i < MAX_SIGNAL; i++)
+		init_completion(&inst->completions[i]);
+
+	inst->workq = create_singlethread_workqueue("workq");
+	if (!inst->workq) {
+		i_vpr_e(inst, "%s: create workq failed\n", __func__);
+		goto fail_create_workq;
+	}
+
+	INIT_DELAYED_WORK(&inst->stats_work, msm_vidc_stats_handler);
+
+	rc = msm_vidc_v4l2_fh_init(inst);
+	if (rc)
+		goto fail_eventq_init;
+
+	rc = msm_vidc_vb2_queue_init(inst);
+	if (rc)
+		goto fail_vb2q_init;
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_inst_init(inst);
+	else if (is_encode_session(inst))
+		rc = msm_venc_inst_init(inst);
+	if (rc)
+		goto fail_inst_init;
+
+	msm_vidc_scale_power(inst, true);
+
+	rc = msm_vidc_session_open(inst);
+	if (rc) {
+		msm_vidc_core_deinit(core, true);
+		goto fail_session_open;
+	}
+
+	inst->debugfs_root =
+		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
+	if (!inst->debugfs_root)
+		i_vpr_h(inst, "%s: debugfs not available\n", __func__);
+
+	return inst;
+
+fail_session_open:
+	if (is_decode_session(inst))
+		msm_vdec_inst_deinit(inst);
+	else if (is_encode_session(inst))
+		msm_venc_inst_deinit(inst);
+fail_inst_init:
+	msm_vidc_vb2_queue_deinit(inst);
+fail_vb2q_init:
+	msm_vidc_v4l2_fh_deinit(inst);
+fail_eventq_init:
+	destroy_workqueue(inst->workq);
+fail_create_workq:
+	msm_vidc_pools_deinit(inst);
+fail_pools_init:
+	msm_vidc_remove_session(inst);
+	msm_vidc_remove_dangling_session(inst);
+fail_add_session:
+	mutex_destroy(&inst->client_lock);
+	mutex_destroy(&inst->ctx_q_lock);
+	mutex_destroy(&inst->lock);
+	vfree(inst);
+	return NULL;
+}
+
+int msm_vidc_close(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	/* print final stats */
+	msm_vidc_print_stats(inst);
+	/* print internal buffer memory usage stats */
+	msm_vidc_print_memory_stats(inst);
+	msm_vidc_session_close(inst);
+	msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__);
+	inst->sub_state = MSM_VIDC_SUB_STATE_NONE;
+	strscpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name));
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	cancel_stats_work_sync(inst);
+	put_inst(inst);
+	msm_vidc_schedule_core_deinit(core);
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 05/33] iris: vidc: add vb2 ops
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (3 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 04/33] iris: add vidc " Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 18:03   ` Nicolas Dufresne
  2023-07-28 13:23 ` [PATCH 06/33] iris: vidc: define video core and instance context Vikash Garodia
                   ` (30 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements vb2 ops for streaming modes for
alloc, free, map and unmap buffers.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |  39 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     | 605 +++++++++++++++++++++
 2 files changed, 644 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
new file mode 100644
index 0000000..12378ce
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_VB2_H_
+#define _MSM_VIDC_VB2_H_
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "msm_vidc_inst.h"
+
+struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
+				    u32 type, const char *func);
+
+/* vb2_mem_ops */
+void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
+		    unsigned long size);
+void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
+			    struct dma_buf *dbuf, unsigned long size);
+
+void msm_vb2_put(void *buf_priv);
+int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma);
+void msm_vb2_detach_dmabuf(void *buf_priv);
+int msm_vb2_map_dmabuf(void *buf_priv);
+void msm_vb2_unmap_dmabuf(void *buf_priv);
+
+/* vb2_ops */
+int msm_vb2_queue_setup(struct vb2_queue *q,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], struct device *alloc_devs[]);
+int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
+int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
+int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count);
+void msm_vb2_stop_streaming(struct vb2_queue *q);
+void msm_vb2_buf_queue(struct vb2_buffer *vb2);
+#endif // _MSM_VIDC_VB2_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
new file mode 100644
index 0000000..c936d95
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
@@ -0,0 +1,605 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "msm_vidc_vb2.h"
+
+struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
+				    u32 type, const char *func)
+{
+	struct vb2_queue *q = NULL;
+
+	if (type == INPUT_MPLANE) {
+		q = inst->bufq[INPUT_PORT].vb2q;
+	} else if (type == OUTPUT_MPLANE) {
+		q = inst->bufq[OUTPUT_PORT].vb2q;
+	} else {
+		i_vpr_e(inst, "%s: invalid buffer type %d\n",
+			__func__, type);
+	}
+	return q;
+}
+
+void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
+		    unsigned long size)
+{
+	return (void *)0xdeadbeef;
+}
+
+void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
+			    struct dma_buf *dbuf, unsigned long size)
+{
+	struct msm_vidc_inst *inst;
+	struct msm_vidc_core *core;
+	struct msm_vidc_buffer *buf = NULL;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+
+	if (!vb || !dev || !dbuf || !vb->vb2_queue) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return NULL;
+	}
+	inst = vb->vb2_queue->drv_priv;
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
+		return NULL;
+	}
+	core = inst->core;
+
+	buf = msm_vidc_fetch_buffer(inst, vb);
+	if (!buf) {
+		i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__);
+		buf = NULL;
+		goto exit;
+	}
+	buf->inst = inst;
+	buf->dmabuf = dbuf;
+
+	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
+		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+			if (ro_buf->dmabuf != buf->dmabuf)
+				continue;
+			print_vidc_buffer(VIDC_LOW, "low ", "attach: found ro buf", inst, ro_buf);
+			buf->attach = ro_buf->attach;
+			ro_buf->attach = NULL;
+			goto exit;
+		}
+	}
+
+	buf->attach = call_mem_op(core, dma_buf_attach, core, dbuf, dev);
+	if (!buf->attach) {
+		buf->attach = NULL;
+		buf = NULL;
+		goto exit;
+	}
+	print_vidc_buffer(VIDC_LOW, "low ", "attach", inst, buf);
+
+exit:
+	if (!buf)
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	put_inst(inst);
+	return buf;
+}
+
+void msm_vb2_put(void *buf_priv)
+{
+}
+
+int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+void msm_vb2_detach_dmabuf(void *buf_priv)
+{
+	struct msm_vidc_buffer *vbuf = buf_priv;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+
+	if (!vbuf || !vbuf->inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+	inst = vbuf->inst;
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
+		return;
+	}
+	core = inst->core;
+
+	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
+		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+			if (ro_buf->dmabuf != vbuf->dmabuf)
+				continue;
+			print_vidc_buffer(VIDC_LOW, "low ", "detach: found ro buf", inst, ro_buf);
+			ro_buf->attach = vbuf->attach;
+			vbuf->attach = NULL;
+			goto exit;
+		}
+	}
+
+	print_vidc_buffer(VIDC_LOW, "low ", "detach", inst, vbuf);
+	if (vbuf->attach && vbuf->dmabuf) {
+		call_mem_op(core, dma_buf_detach, core, vbuf->dmabuf, vbuf->attach);
+		vbuf->attach = NULL;
+	}
+
+exit:
+	vbuf->dmabuf = NULL;
+	vbuf->inst = NULL;
+}
+
+int msm_vb2_map_dmabuf(void *buf_priv)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *buf = buf_priv;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+
+	if (!buf || !buf->inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	inst = buf->inst;
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
+		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+			if (ro_buf->dmabuf != buf->dmabuf)
+				continue;
+			print_vidc_buffer(VIDC_LOW, "low ", "map: found ro buf", inst, ro_buf);
+			buf->sg_table = ro_buf->sg_table;
+			buf->device_addr = ro_buf->device_addr;
+			ro_buf->sg_table = NULL;
+			goto exit;
+		}
+	}
+
+	buf->sg_table = call_mem_op(core, dma_buf_map_attachment, core, buf->attach);
+	if (!buf->sg_table || !buf->sg_table->sgl) {
+		buf->sg_table = NULL;
+		rc = -ENOMEM;
+		goto exit;
+	}
+	buf->device_addr = sg_dma_address(buf->sg_table->sgl);
+	print_vidc_buffer(VIDC_HIGH, "high", "map", inst, buf);
+
+exit:
+	if (rc)
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	put_inst(inst);
+	return rc;
+}
+
+void msm_vb2_unmap_dmabuf(void *buf_priv)
+{
+	struct msm_vidc_buffer *vbuf = buf_priv;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+
+	if (!vbuf || !vbuf->inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+	inst = vbuf->inst;
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
+		return;
+	}
+	core = inst->core;
+
+	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
+		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+			if (ro_buf->dmabuf != vbuf->dmabuf)
+				continue;
+			print_vidc_buffer(VIDC_LOW, "low ", "unmap: found ro buf", inst, ro_buf);
+			ro_buf->sg_table = vbuf->sg_table;
+			vbuf->sg_table = NULL;
+			vbuf->device_addr = 0x0;
+			goto exit;
+		}
+	}
+
+	print_vidc_buffer(VIDC_HIGH, "high", "unmap", inst, vbuf);
+	if (vbuf->attach && vbuf->sg_table) {
+		call_mem_op(core, dma_buf_unmap_attachment, core, vbuf->attach, vbuf->sg_table);
+		vbuf->sg_table = NULL;
+		vbuf->device_addr = 0x0;
+	}
+
+exit:
+	return;
+}
+
+int msm_vb2_queue_setup(struct vb2_queue *q,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], struct device *alloc_devs[])
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+	struct msm_vidc_core *core;
+	int port;
+	struct v4l2_format *f;
+	enum msm_vidc_buffer_type buffer_type = 0;
+	enum msm_vidc_buffer_region region = MSM_VIDC_REGION_NONE;
+	struct context_bank_info *cb = NULL;
+	struct msm_vidc_buffers *buffers;
+
+	if (!q || !num_buffers || !num_planes ||
+	    !sizes || !q->drv_priv) {
+		d_vpr_e("%s: invalid params, q = %pK, %pK, %pK\n",
+			__func__, q, num_buffers, num_planes);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	if (is_state(inst, MSM_VIDC_STREAMING)) {
+		i_vpr_e(inst, "%s: invalid state %d\n", __func__, inst->state);
+		return -EINVAL;
+	}
+
+	port = v4l2_type_to_driver_port(inst, q->type, __func__);
+	if (port < 0)
+		return -EINVAL;
+
+	/* prepare dependency list once per session */
+	if (!inst->caps_list_prepared) {
+		rc = msm_vidc_prepare_dependency_list(inst);
+		if (rc)
+			return rc;
+		inst->caps_list_prepared = true;
+	}
+
+	/* adjust v4l2 properties for master port */
+	if ((is_encode_session(inst) && port == OUTPUT_PORT) ||
+	    (is_decode_session(inst) && port == INPUT_PORT)) {
+		rc = msm_vidc_adjust_v4l2_properties(inst);
+		if (rc) {
+			i_vpr_e(inst, "%s: failed to adjust properties\n", __func__);
+			return rc;
+		}
+	}
+
+	if (*num_planes && (port == INPUT_PORT || port == OUTPUT_PORT)) {
+		f = &inst->fmts[port];
+		if (*num_planes != f->fmt.pix_mp.num_planes) {
+			i_vpr_e(inst, "%s: requested num_planes %d not supported %d\n",
+				__func__, *num_planes, f->fmt.pix_mp.num_planes);
+			return -EINVAL;
+		}
+		if (sizes[0] < inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage) {
+			i_vpr_e(inst, "%s: requested size %d not acceptable\n",
+				__func__, sizes[0]);
+			return -EINVAL;
+		}
+	}
+
+	buffer_type = v4l2_type_to_driver(q->type, __func__);
+	if (!buffer_type)
+		return -EINVAL;
+
+	rc = msm_vidc_free_buffers(inst, buffer_type);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to free buffers, type %s\n",
+			__func__, v4l2_type_name(q->type));
+		return rc;
+	}
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	buffers->min_count = call_session_op(core, min_count, inst, buffer_type);
+	buffers->extra_count = call_session_op(core, extra_count, inst, buffer_type);
+	if (*num_buffers < buffers->min_count + buffers->extra_count)
+		*num_buffers = buffers->min_count + buffers->extra_count;
+	buffers->actual_count = *num_buffers;
+	*num_planes = 1;
+
+	buffers->size = call_session_op(core, buffer_size, inst, buffer_type);
+
+	inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage = buffers->size;
+	sizes[0] = inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	rc = msm_vidc_allocate_buffers(inst, buffer_type, *num_buffers);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to allocate buffers, type %s\n",
+			__func__, v4l2_type_name(q->type));
+		return rc;
+	}
+
+	region = call_mem_op(core, buffer_region, inst, buffer_type);
+	cb = msm_vidc_get_context_bank_for_region(core, region);
+	if (!cb) {
+		d_vpr_e("%s: Failed to get context bank device\n",
+			__func__);
+		return -EIO;
+	}
+	q->dev = cb->dev;
+
+	i_vpr_h(inst,
+		"queue_setup: type %s num_buffers %d sizes[0] %d cb %s\n",
+		v4l2_type_name(q->type), *num_buffers, sizes[0], cb->name);
+	return rc;
+}
+
+int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+
+	if (!q || !q->drv_priv) {
+		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q);
+	if (rc) {
+		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
+{
+	enum msm_vidc_buffer_type buf_type;
+	int rc = 0;
+
+	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+		return -EINVAL;
+	}
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
+
+	if (!inst->once_per_session_set) {
+		inst->once_per_session_set = true;
+		rc = msm_vidc_session_set_codec(inst);
+		if (rc)
+			return rc;
+
+		if (is_encode_session(inst)) {
+			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
+								       MSM_VIDC_BUF_ARP);
+			if (rc)
+				return rc;
+		} else if (is_decode_session(inst)) {
+			rc = msm_vidc_session_set_default_header(inst);
+			if (rc)
+				return rc;
+
+			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
+								       MSM_VIDC_BUF_PERSIST);
+			if (rc)
+				return rc;
+		}
+	}
+
+	if (is_decode_session(inst))
+		inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
+
+	msm_vidc_allow_dcvs(inst);
+	msm_vidc_power_data_reset(inst);
+
+	if (q->type == INPUT_MPLANE) {
+		if (is_decode_session(inst))
+			rc = msm_vdec_streamon_input(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_streamon_input(inst);
+	} else if (q->type == OUTPUT_MPLANE) {
+		if (is_decode_session(inst))
+			rc = msm_vdec_streamon_output(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_streamon_output(inst);
+	}
+	if (rc)
+		return rc;
+
+	/* print final buffer counts & size details */
+	msm_vidc_print_buffer_info(inst);
+
+	/* print internal buffer memory usage stats */
+	msm_vidc_print_memory_stats(inst);
+
+	buf_type = v4l2_type_to_driver(q->type, __func__);
+	if (!buf_type)
+		return -EINVAL;
+
+	/* queue pending buffers */
+	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
+	if (rc)
+		return rc;
+
+	/* initialize statistics timer(one time) */
+	if (!inst->stats.time_ms)
+		inst->stats.time_ms = ktime_get_ns() / 1000 / 1000;
+
+	/* schedule to print buffer statistics */
+	rc = schedule_stats_work(inst);
+	if (rc)
+		return rc;
+
+	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
+	    (q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
+		rc = msm_vidc_get_properties(inst);
+		if (rc)
+			return rc;
+	}
+
+	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
+	return rc;
+}
+
+int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
+{
+	int rc = 0;
+
+	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+		return -EINVAL;
+	}
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
+
+	if (q->type == INPUT_MPLANE) {
+		if (is_decode_session(inst))
+			rc = msm_vdec_streamoff_input(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_streamoff_input(inst);
+	} else if (q->type == OUTPUT_MPLANE) {
+		if (is_decode_session(inst))
+			rc = msm_vdec_streamoff_output(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_streamoff_output(inst);
+	}
+	if (rc)
+		return rc;
+
+	/* Input port streamoff */
+	if (q->type == INPUT_MPLANE) {
+		/* flush timestamps list */
+		msm_vidc_flush_ts(inst);
+	}
+
+	/* print internal buffer memory usage stats */
+	msm_vidc_print_memory_stats(inst);
+
+	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
+	return rc;
+}
+
+void msm_vb2_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
+		return;
+	}
+	inst = q->drv_priv;
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q);
+	if (rc) {
+		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+}
+
+void msm_vb2_buf_queue(struct vb2_buffer *vb2)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+	struct dma_buf *dbuf = NULL;
+	struct msm_vidc_core *core;
+	u64 ktime_ns = ktime_get_ns();
+
+	if (!vb2) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	inst = vb2_get_drv_priv(vb2->vb2_queue);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+	core = inst->core;
+
+	if (!vb2->planes[0].bytesused) {
+		if (vb2->type == INPUT_MPLANE) {
+			/* Expecting non-zero filledlen on INPUT port */
+			i_vpr_e(inst,
+				"%s: zero bytesused input buffer not supported\n", __func__);
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+
+	inst->last_qbuf_time_ns = ktime_ns;
+
+	if (vb2->type == INPUT_MPLANE) {
+		rc = msm_vidc_update_input_rate(inst, div_u64(ktime_ns, 1000));
+		if (rc)
+			goto exit;
+	}
+
+	/*
+	 * Userspace may close fd(from other thread), before driver attempts to call
+	 * dma_buf_get() in qbuf(FTB) sequence(for decoder output buffer) which may
+	 * lead to different kind of security issues. Add check to compare if dma_buf
+	 * address is matching with driver dma_buf_get returned address for that fd.
+	 */
+
+	dbuf = call_mem_op(core, dma_buf_get, inst, vb2->planes[0].m.fd);
+	if (dbuf != vb2->planes[0].dbuf) {
+		i_vpr_e(inst, "%s: invalid dmabuf address 0x%p expected 0x%p\n",
+			__func__, dbuf, vb2->planes[0].dbuf);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_qbuf(inst, vb2);
+	else if (is_encode_session(inst))
+		rc = msm_venc_qbuf(inst, vb2);
+	else
+		rc = -EINVAL;
+	if (rc) {
+		print_vb2_buffer("failed vb2-qbuf", inst, vb2);
+		goto exit;
+	}
+
+exit:
+	if (dbuf)
+		call_mem_op(core, dma_buf_put, inst, dbuf);
+
+	if (rc) {
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		vb2_buffer_done(vb2, VB2_BUF_STATE_ERROR);
+	}
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 06/33] iris: vidc: define video core and instance context
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (4 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 05/33] iris: vidc: add vb2 ops Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 15:47   ` Bryan O'Donoghue
  2023-07-28 13:23 ` [PATCH 07/33] iris: iris: add video encoder files Vikash Garodia
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements video core and instance context structure and
associated core and session ops.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_core.h    | 165 ++++++++++++++++
 .../platform/qcom/iris/vidc/inc/msm_vidc_inst.h    | 207 +++++++++++++++++++++
 2 files changed, 372 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
new file mode 100644
index 0000000..cd8804ff
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_CORE_H_
+#define _MSM_VIDC_CORE_H_
+
+#include <linux/platform_device.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_state.h"
+#include "resources.h"
+#include "venus_hfi_queue.h"
+
+#define MAX_EVENTS   30
+
+#define call_iris_op(d, op, ...)			\
+	(((d) && (d)->iris_ops && (d)->iris_ops->op) ? \
+	((d)->iris_ops->op(__VA_ARGS__)) : 0)
+
+struct msm_vidc_iris_ops {
+	int (*boot_firmware)(struct msm_vidc_core *core);
+	int (*raise_interrupt)(struct msm_vidc_core *core);
+	int (*clear_interrupt)(struct msm_vidc_core *core);
+	int (*prepare_pc)(struct msm_vidc_core *core);
+	int (*power_on)(struct msm_vidc_core *core);
+	int (*power_off)(struct msm_vidc_core *core);
+	int (*watchdog)(struct msm_vidc_core *core, u32 intr_status);
+};
+
+struct msm_vidc_mem_addr {
+	u32 align_device_addr;
+	u8 *align_virtual_addr;
+	u32 mem_size;
+	struct msm_vidc_mem mem;
+};
+
+struct msm_vidc_iface_q_info {
+	void *q_hdr;
+	struct msm_vidc_mem_addr q_array;
+};
+
+struct msm_video_device {
+	enum msm_vidc_domain_type              type;
+	struct video_device                    vdev;
+	struct v4l2_m2m_dev                   *m2m_dev;
+};
+
+struct msm_vidc_core_power {
+	u64 clk_freq;
+	u64 bw_ddr;
+	u64 bw_llcc;
+};
+
+/**
+ * struct msm_vidc_core - holds core parameters valid for all instances
+ *
+ * @pdev: refernce to platform device structure
+ * @vdev: a reference to video device structure for encoder & decoder instances
+ * @v4l2_dev : a holder for v4l2 device structure
+ * @instances: a list_head of all instances
+ * @dangling_instances : a list_head of all dangling instances
+ * @debugfs_parent: debugfs node for msm_vidc
+ * @debugfs_root: debugfs node for core info
+ * @fw_version: a holder for fw version
+ * @state: a structure of core states
+ * @state_handle: a handler for core state change
+ * @sub_state: enumeration of core substate
+ * @sub_state_name: holder for core substate name
+ * @lock: a lock for this strucure
+ * @resources: a structure for core resources
+ * @platform: a structure for platform data
+ * @intr_status: interrupt status
+ * @spur_count: counter for spurious interrupt
+ * @reg_count: counter for interrupts
+ * @enc_codecs_count: encoder codec count
+ * @dec_codecs_count: decoder codec count
+ * @capabilities: an array for supported core capabilities
+ * @inst_caps: a pointer to supported instance capabilities
+ * @sfr: SFR register memory
+ * @iface_q_table: Interface queue table memory
+ * @iface_queues: a array of interface queues info
+ * @pm_work: delayed work to handle power collapse
+ * @pm_workq: workqueue for power collapse work
+ * @batch_workq: workqueue for batching
+ * @fw_unload_work: delayed work for fw unload
+ * @power: a sturture for core power
+ * @skip_pc_count: a counter for skipped power collpase
+ * @last_packet_type: holder for last packet type info
+ * @packet: pointer to packet from driver to fw
+ * @packet_size: size of packet
+ * @response_packet: a pointer to response packet from fw to driver
+ * @v4l2_file_ops: a pointer to v4l2 file ops
+ * @v4l2_ioctl_ops_enc: a pointer to v4l2 ioctl ops for encoder
+ * @v4l2_ioctl_ops_dec: a pointer to v4l2 ioclt ops for decoder
+ * @v4l2_ctrl_ops: a pointer to v4l2 control ops
+ * @vb2_ops: a pointer to vb2 ops
+ * @vb2_mem_ops: a pointer to vb2 memory ops
+ * @v4l2_m2m_ops: a pointer to v4l2_mem ops
+ * @iris_ops: a pointer to iris ops
+ * @res_ops: a pointer to resource management ops
+ * @session_ops: a pointer to session level ops
+ * @mem_ops: a pointer to memory management ops
+ * @header_id: id of packet header
+ * @packet_id: id of packet
+ * @sys_init_id: id of sys init packet
+ */
+
+struct msm_vidc_core {
+	struct platform_device                *pdev;
+	struct msm_video_device                vdev[2];
+	struct v4l2_device                     v4l2_dev;
+	struct list_head                       instances;
+	struct list_head                       dangling_instances;
+	struct dentry                         *debugfs_parent;
+	struct dentry                         *debugfs_root;
+	char                                   fw_version[MAX_NAME_LENGTH];
+	enum msm_vidc_core_state               state;
+	int                                  (*state_handle)(struct msm_vidc_core *core,
+							     enum msm_vidc_core_event_type type,
+							     struct msm_vidc_event_data *data);
+	enum msm_vidc_core_sub_state           sub_state;
+	char                                   sub_state_name[MAX_NAME_LENGTH];
+	struct mutex                           lock; /* lock for core structure */
+	struct msm_vidc_resource              *resource;
+	struct msm_vidc_platform              *platform;
+	u32                                    intr_status;
+	u32                                    spur_count;
+	u32                                    reg_count;
+	u32                                    enc_codecs_count;
+	u32                                    dec_codecs_count;
+	struct msm_vidc_core_capability        capabilities[CORE_CAP_MAX + 1];
+	struct msm_vidc_inst_capability       *inst_caps;
+	struct msm_vidc_mem_addr               sfr;
+	struct msm_vidc_mem_addr               iface_q_table;
+	struct msm_vidc_iface_q_info           iface_queues[VIDC_IFACEQ_NUMQ];
+	struct delayed_work                    pm_work;
+	struct workqueue_struct               *pm_workq;
+	struct workqueue_struct               *batch_workq;
+	struct delayed_work                    fw_unload_work;
+	struct msm_vidc_core_power             power;
+	u32                                    skip_pc_count;
+	u32                                    last_packet_type;
+	u8                                    *packet;
+	u32                                    packet_size;
+	u8                                    *response_packet;
+	struct v4l2_file_operations           *v4l2_file_ops;
+	const struct v4l2_ioctl_ops                 *v4l2_ioctl_ops_enc;
+	const struct v4l2_ioctl_ops                 *v4l2_ioctl_ops_dec;
+	const struct v4l2_ctrl_ops                  *v4l2_ctrl_ops;
+	const struct vb2_ops                        *vb2_ops;
+	struct vb2_mem_ops                    *vb2_mem_ops;
+	struct v4l2_m2m_ops                   *v4l2_m2m_ops;
+	struct msm_vidc_iris_ops              *iris_ops;
+	const struct msm_vidc_resources_ops   *res_ops;
+	struct msm_vidc_session_ops           *session_ops;
+	const struct msm_vidc_memory_ops      *mem_ops;
+	u32                                    header_id;
+	u32                                    packet_id;
+	u32                                    sys_init_id;
+};
+
+#endif // _MSM_VIDC_CORE_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
new file mode 100644
index 0000000..96c8903
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_INST_H_
+#define _MSM_VIDC_INST_H_
+
+#include "hfi_property.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_state.h"
+
+#define call_session_op(c, op, ...)			\
+	(((c) && (c)->session_ops && (c)->session_ops->op) ? \
+	((c)->session_ops->op(__VA_ARGS__)) : 0)
+
+struct msm_vidc_session_ops {
+	u64 (*calc_freq)(struct msm_vidc_inst *inst, u32 data_size);
+	int (*calc_bw)(struct msm_vidc_inst *inst,
+		       struct vidc_bus_vote_data *vote_data);
+	int (*decide_work_route)(struct msm_vidc_inst *inst);
+	int (*decide_work_mode)(struct msm_vidc_inst *inst);
+	int (*decide_quality_mode)(struct msm_vidc_inst *inst);
+	int (*buffer_size)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
+	int (*min_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
+	int (*extra_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
+	int (*ring_buf_count)(struct msm_vidc_inst *inst, u32 data_size);
+};
+
+struct msm_vidc_mem_list_info {
+	struct msm_vidc_mem_list        bin;
+	struct msm_vidc_mem_list        arp;
+	struct msm_vidc_mem_list        comv;
+	struct msm_vidc_mem_list        non_comv;
+	struct msm_vidc_mem_list        line;
+	struct msm_vidc_mem_list        dpb;
+	struct msm_vidc_mem_list        persist;
+	struct msm_vidc_mem_list        vpss;
+};
+
+struct msm_vidc_buffers_info {
+	struct msm_vidc_buffers        input;
+	struct msm_vidc_buffers        output;
+	struct msm_vidc_buffers        read_only;
+	struct msm_vidc_buffers        bin;
+	struct msm_vidc_buffers        arp;
+	struct msm_vidc_buffers        comv;
+	struct msm_vidc_buffers        non_comv;
+	struct msm_vidc_buffers        line;
+	struct msm_vidc_buffers        dpb;
+	struct msm_vidc_buffers        persist;
+	struct msm_vidc_buffers        vpss;
+};
+
+struct buf_queue {
+	struct vb2_queue *vb2q;
+};
+
+/**
+ * struct msm_vidc_inst - holds per instance parameters
+ *
+ * @list: used for attach an instance to the core
+ * @lock: lock for this structure
+ * @ctx_q_lock:  lock to serialize ioctls calls related to queues
+ * @client_lock: lock to serialize ioctls
+ * @state: instnace state
+ * @event_handle: handler for different v4l2 ioctls
+ * @sub_state: substate of instance
+ * @sub_state_name: substate name
+ * @domain: domain type: encoder or decoder
+ * @codec: codec type
+ * @core: pointer to core structure
+ * @kref: instance reference
+ * @session_id: id of current session
+ * @debug_str: debug string
+ * @packet: HFI packet
+ * @packet_size: HFI packet size
+ * @fmts: structure of v4l2_format
+ * @ctrl_handler: reference of v4l2 ctrl handler
+ * @fh: reference of v4l2 file handler
+ * @m2m_dev: m2m device handle
+ * @m2m_ctx: m2m device context
+ * @num_ctrls: supported number of controls
+ * @hfi_rc_type: type of HFI rate control
+ * @hfi_layer_type: type of HFI layer encoding
+ * @bufq: array of vb2 queue
+ * @crop: structure of crop info
+ * @compose: structure of compose info
+ * @power: structure of power info
+ * @bus_data: structure of bus data
+ * @pool: array of memory pool of buffers
+ * @buffers: structure of buffer info
+ * @mem_info: structure of memory info
+ * @timestamps: structure of timestamp related info
+ * @subcr_params: array of subscription params which driver subscribes to fw
+ * @hfi_frame_info: structure of frame info
+ * @decode_batch: strtucre of decode batch
+ * @decode_vpp_delay: structure for vpp delay related info
+ * @session_idle: structure of idle session related info
+ * @stats_work: delayed work for buffer stats
+ * @workq: pointer to workqueue
+ * @enc_input_crs: list head of input compression rations
+ * @dmabuf_tracker: list head of dambuf tracker
+ * @input_timer_list: list head of input timer
+ * @caps_list: list head of capability
+ * @children_list: list head of children list of caps
+ * @firmware_list: list head of fw list of cap which will be set to cap
+ * @buffer_stats_list: list head of buffer stats
+ * @once_per_session_set: boolean to set once per session property
+ * @ipsc_properties_set: boolean to set ipsc properties to fw
+ * @opsc_properties_set: boolean to set opsc properties to fw
+ * @caps_list_prepared: boolean to prepare capability list
+ * @debugfs_root: root of debugfs
+ * @debug_count: count for ETBs, EBDs, FTBs and FBDs
+ * @stats: structure for bw stats
+ * @capabilities: array of supported instance capabilities
+ * @completions: structure of signal completions
+ * @active: boolean for active instances
+ * @last_qbuf_time_ns: time of last qbuf to driver
+ * @initial_time_us: start timestamp
+ * @max_input_data_size: max size of input data
+ * @dpb_list_payload: array of dpb buffers
+ * @input_dpb_list_enabled: boolean for input dpb buffer list
+ * @output_dpb_list_enabled: boolean for output dpb buffer list
+ * @max_rate: max input rate
+ * @has_bframe: boolean for B frame
+ * @ir_enabled: boolean for intra refresh
+ * @iframe: boolean for I frame
+ * @fw_min_count: minimnum count of buffers needed by fw
+ */
+
+struct msm_vidc_inst {
+	struct list_head                   list;
+	struct mutex                       lock; /* instance lock */
+	/* lock to serialize IOCTL calls related to queues */
+	struct mutex                       ctx_q_lock;
+	struct mutex                       client_lock; /* lock to serialize IOCTLs */
+	enum msm_vidc_state                state;
+	int                              (*event_handle)(struct msm_vidc_inst *inst,
+							 enum msm_vidc_event event, void *data);
+	enum msm_vidc_sub_state            sub_state;
+	char                               sub_state_name[MAX_NAME_LENGTH];
+	enum msm_vidc_domain_type          domain;
+	enum msm_vidc_codec_type           codec;
+	void                              *core;
+	struct kref                        kref;
+	u32                                session_id;
+	u8                                 debug_str[24];
+	void                              *packet;
+	u32                                packet_size;
+	struct v4l2_format                 fmts[MAX_PORT];
+	struct v4l2_ctrl_handler           ctrl_handler;
+	struct v4l2_fh                     fh;
+	struct v4l2_m2m_dev               *m2m_dev;
+	struct v4l2_m2m_ctx               *m2m_ctx;
+	u32                                num_ctrls;
+	enum hfi_rate_control              hfi_rc_type;
+	enum hfi_layer_encoding_type       hfi_layer_type;
+	struct buf_queue                   bufq[MAX_PORT];
+	struct msm_vidc_rectangle          crop;
+	struct msm_vidc_rectangle          compose;
+	struct msm_vidc_power              power;
+	struct vidc_bus_vote_data          bus_data;
+	struct msm_memory_pool             pool[MSM_MEM_POOL_MAX];
+	struct msm_vidc_buffers_info       buffers;
+	struct msm_vidc_mem_list_info      mem_info;
+	struct msm_vidc_timestamps         timestamps;
+	struct msm_vidc_subscription_params       subcr_params[MAX_PORT];
+	struct msm_vidc_hfi_frame_info     hfi_frame_info;
+	struct msm_vidc_decode_batch       decode_batch;
+	struct msm_vidc_decode_vpp_delay   decode_vpp_delay;
+	struct msm_vidc_session_idle       session_idle;
+	struct delayed_work                stats_work;
+	struct workqueue_struct           *workq;
+	struct list_head                   enc_input_crs;
+	struct list_head                   dmabuf_tracker; /* struct msm_memory_dmabuf */
+	struct list_head                   input_timer_list; /* struct msm_vidc_input_timer */
+	struct list_head                   caps_list;
+	struct list_head                   children_list; /* struct msm_vidc_inst_cap_entry */
+	struct list_head                   firmware_list; /* struct msm_vidc_inst_cap_entry */
+	struct list_head                   buffer_stats_list; /* struct msm_vidc_buffer_stats */
+	bool                               once_per_session_set;
+	bool                               ipsc_properties_set;
+	bool                               opsc_properties_set;
+	bool                               caps_list_prepared;
+	struct dentry                     *debugfs_root;
+	struct debug_buf_count             debug_count;
+	struct msm_vidc_statistics         stats;
+	struct msm_vidc_inst_cap           capabilities[INST_CAP_MAX + 1];
+	struct completion                  completions[MAX_SIGNAL];
+	bool                               active;
+	u64                                last_qbuf_time_ns;
+	u64                                initial_time_us;
+	u32                                max_input_data_size;
+	u32                                dpb_list_payload[MAX_DPB_LIST_ARRAY_SIZE];
+	bool                               input_dpb_list_enabled;
+	bool                               output_dpb_list_enabled;
+	u32                                max_rate;
+	bool                               has_bframe;
+	bool                               ir_enabled;
+	bool                               iframe;
+	u32                                fw_min_count;
+};
+
+#endif // _MSM_VIDC_INST_H_
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 07/33] iris: iris: add video encoder files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (5 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 06/33] iris: vidc: define video core and instance context Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 08/33] iris: vidc: add video decoder files Vikash Garodia
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements video encoder functionalities of the driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/msm_venc.h   |   34 +
 .../media/platform/qcom/iris/vidc/src/msm_venc.c   | 1484 ++++++++++++++++++++
 2 files changed, 1518 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_venc.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
new file mode 100644
index 0000000..bb0a395
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_inst.h"
+
+int msm_venc_streamoff_input(struct msm_vidc_inst *inst);
+int msm_venc_streamon_input(struct msm_vidc_inst *inst);
+int msm_venc_streamoff_output(struct msm_vidc_inst *inst);
+int msm_venc_streamon_output(struct msm_vidc_inst *inst);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
+int msm_venc_stop_cmd(struct msm_vidc_inst *inst);
+int msm_venc_start_cmd(struct msm_vidc_inst *inst);
+int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_venc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_venc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_venc_s_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *s_parm);
+int msm_venc_g_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *s_parm);
+int msm_venc_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub);
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_inst_deinit(struct msm_vidc_inst *inst);
+
+#endif // _MSM_VENC_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_venc.c b/drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
new file mode 100644
index 0000000..4962716
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
@@ -0,0 +1,1484 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_packet.h"
+#include "msm_media_info.h"
+#include "msm_venc.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "venus_hfi.h"
+
+static const u32 msm_venc_input_set_prop[] = {
+	HFI_PROP_COLOR_FORMAT,
+	HFI_PROP_RAW_RESOLUTION,
+	HFI_PROP_CROP_OFFSETS,
+	HFI_PROP_LINEAR_STRIDE_SCANLINE,
+	HFI_PROP_SIGNAL_COLOR_INFO,
+};
+
+static const u32 msm_venc_output_set_prop[] = {
+	HFI_PROP_BITSTREAM_RESOLUTION,
+	HFI_PROP_CROP_OFFSETS,
+};
+
+static const u32 msm_venc_input_subscribe_for_properties[] = {
+	HFI_PROP_NO_OUTPUT,
+};
+
+static const u32 msm_venc_output_subscribe_for_properties[] = {
+	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_BUFFER_MARK,
+	HFI_PROP_WORST_COMPRESSION_RATIO,
+};
+
+static const u32 msm_venc_output_internal_buffer_type[] = {
+	MSM_VIDC_BUF_BIN,
+	MSM_VIDC_BUF_COMV,
+	MSM_VIDC_BUF_NON_COMV,
+	MSM_VIDC_BUF_LINE,
+	MSM_VIDC_BUF_DPB,
+};
+
+static const u32 msm_venc_input_internal_buffer_type[] = {
+	MSM_VIDC_BUF_VPSS,
+};
+
+struct msm_venc_prop_type_handle {
+	u32 type;
+	int (*handle)(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+};
+
+static int msm_venc_codec_change(struct msm_vidc_inst *inst, u32 v4l2_codec)
+{
+	int rc = 0;
+	bool session_init = false;
+
+	if (!inst->codec)
+		session_init = true;
+
+	if (inst->codec && inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat == v4l2_codec)
+		return 0;
+
+	i_vpr_h(inst, "%s: codec changed from %s to %s\n",
+		__func__, v4l2_pixelfmt_name(inst, inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat),
+		v4l2_pixelfmt_name(inst, v4l2_codec));
+
+	inst->codec = v4l2_codec_to_driver(inst, v4l2_codec, __func__);
+	if (!inst->codec) {
+		i_vpr_e(inst, "%s: invalid codec %#x\n", __func__, v4l2_codec);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat = v4l2_codec;
+	rc = msm_vidc_update_debug_str(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_get_inst_capability(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_ctrl_handler_init(inst, session_init);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_update_buffer_count(inst, INPUT_PORT);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT);
+	if (rc)
+		goto exit;
+
+exit:
+	return rc;
+}
+
+/* todo: add logs for each property once finalised */
+static int msm_venc_set_colorformat(struct msm_vidc_inst *inst,
+				    enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 pixelformat;
+	enum msm_vidc_colorformat_type colorformat;
+	u32 hfi_colorformat;
+
+	if (port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat;
+	colorformat = v4l2_colorformat_to_driver(inst, pixelformat, __func__);
+	if (!(colorformat & inst->capabilities[PIX_FMTS].step_or_mask)) {
+		i_vpr_e(inst, "%s: invalid pixelformat %s\n",
+			__func__, v4l2_pixelfmt_name(inst, pixelformat));
+		return -EINVAL;
+	}
+
+	hfi_colorformat = get_hfi_colorformat(inst, colorformat);
+	i_vpr_h(inst, "%s: hfi colorformat: %#x", __func__,
+		hfi_colorformat);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_COLOR_FORMAT,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32_ENUM,
+					&hfi_colorformat,
+					sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_stride_scanline(struct msm_vidc_inst *inst,
+					enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 color_format, stride_y, scanline_y;
+	u32 stride_uv = 0, scanline_uv = 0;
+	u32 payload[2];
+
+	if (port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	color_format = inst->capabilities[PIX_FMTS].value;
+	if (!is_linear_colorformat(color_format)) {
+		i_vpr_h(inst,
+			"%s: not a linear color fmt, property is not set\n",
+			__func__);
+		return 0;
+	}
+
+	if (is_rgba_colorformat(color_format)) {
+		stride_y = video_rgb_stride_pix(color_format,
+						inst->fmts[INPUT_PORT].fmt.pix_mp.width);
+		scanline_y = video_rgb_scanlines(color_format,
+						 inst->fmts[INPUT_PORT].fmt.pix_mp.height);
+	} else {
+		stride_y = video_y_stride_pix(color_format,
+					      inst->fmts[INPUT_PORT].fmt.pix_mp.width);
+		scanline_y = video_y_scanlines(color_format,
+					       inst->fmts[INPUT_PORT].fmt.pix_mp.height);
+	}
+	if (color_format == MSM_VIDC_FMT_NV12 ||
+	    color_format == MSM_VIDC_FMT_P010 ||
+	    color_format == MSM_VIDC_FMT_NV21) {
+		stride_uv = stride_y;
+		scanline_uv = scanline_y / 2;
+	}
+
+	payload[0] = stride_y << 16 | scanline_y;
+	payload[1] = stride_uv << 16 | scanline_uv;
+	i_vpr_h(inst,
+		"%s: y: stride %d scanline, %d uv: stride %d scanline_uv %d",
+		__func__,
+		stride_y, scanline_y, stride_uv, scanline_uv);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_LINEAR_STRIDE_SCANLINE,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_64_PACKED,
+					&payload,
+					sizeof(u64));
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int msm_venc_set_raw_resolution(struct msm_vidc_inst *inst,
+				       enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 resolution;
+
+	if (port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	resolution = (inst->fmts[port].fmt.pix_mp.width << 16) |
+		inst->fmts[port].fmt.pix_mp.height;
+	i_vpr_h(inst, "%s: width: %d height: %d\n", __func__,
+		inst->fmts[port].fmt.pix_mp.width, inst->fmts[port].fmt.pix_mp.height);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_RAW_RESOLUTION,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_32_PACKED,
+					&resolution,
+					sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_bitstream_resolution(struct msm_vidc_inst *inst,
+					     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 resolution;
+
+	if (port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	resolution = (inst->fmts[port].fmt.pix_mp.width << 16) |
+		inst->fmts[port].fmt.pix_mp.height;
+	i_vpr_h(inst, "%s: width: %d height: %d\n", __func__,
+		inst->fmts[port].fmt.pix_mp.width,
+		inst->fmts[port].fmt.pix_mp.height);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_BITSTREAM_RESOLUTION,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_32_PACKED,
+					&resolution,
+					sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_crop_offsets(struct msm_vidc_inst *inst,
+				     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 left_offset, top_offset, right_offset, bottom_offset;
+	u32 crop[2] = {0};
+	u32 width, height;
+
+	if (port != OUTPUT_PORT && port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	if (port == INPUT_PORT) {
+		left_offset = inst->crop.left;
+		top_offset = inst->crop.top;
+		width = inst->crop.width;
+		height = inst->crop.height;
+	} else {
+		left_offset = inst->compose.left;
+		top_offset = inst->compose.top;
+		width = inst->compose.width;
+		height = inst->compose.height;
+		if (is_rotation_90_or_270(inst)) {
+			width = inst->compose.height;
+			height = inst->compose.width;
+		}
+	}
+
+	right_offset = (inst->fmts[port].fmt.pix_mp.width - width);
+	bottom_offset = (inst->fmts[port].fmt.pix_mp.height - height);
+
+	crop[0] = left_offset << 16 | top_offset;
+	crop[1] = right_offset << 16 | bottom_offset;
+	i_vpr_h(inst,
+		"%s: l_off: %d t_off: %d r_off: %d b_off: %d",
+		__func__,
+		left_offset, top_offset, right_offset, bottom_offset);
+
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_CROP_OFFSETS,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_64_PACKED,
+					&crop,
+					sizeof(u64));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_colorspace(struct msm_vidc_inst *inst,
+				   enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 primaries = MSM_VIDC_PRIMARIES_RESERVED;
+	u32 matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED;
+	u32 transfer_char = MSM_VIDC_TRANSFER_RESERVED;
+	u32 full_range = 0;
+	u32 colour_description_present_flag = 0;
+	u32 video_signal_type_present_flag = 0, payload = 0;
+	/* Unspecified video format */
+	u32 video_format = 5;
+	struct v4l2_format *input_fmt;
+	u32 pix_fmt;
+	struct v4l2_pix_format_mplane *pixmp = NULL;
+
+	if (port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	if (inst->capabilities[SIGNAL_COLOR_INFO].flags & CAP_FLAG_CLIENT_SET) {
+		i_vpr_h(inst, "%s: client configured colorspace via control\n", __func__);
+		return 0;
+	}
+
+	input_fmt = &inst->fmts[INPUT_PORT];
+	pixmp = &inst->fmts[port].fmt.pix_mp;
+	pix_fmt = v4l2_colorformat_to_driver(inst,
+					     input_fmt->fmt.pix_mp.pixelformat, __func__);
+	if (pixmp->colorspace != V4L2_COLORSPACE_DEFAULT ||
+	    pixmp->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT ||
+	    pixmp->xfer_func != V4L2_XFER_FUNC_DEFAULT) {
+		colour_description_present_flag = 1;
+		video_signal_type_present_flag = 1;
+		primaries = v4l2_color_primaries_to_driver(inst,
+							   pixmp->colorspace, __func__);
+		matrix_coeff = v4l2_matrix_coeff_to_driver(inst,
+							   pixmp->ycbcr_enc, __func__);
+		transfer_char = v4l2_transfer_char_to_driver(inst,
+							     pixmp->xfer_func, __func__);
+	} else if (is_rgba_colorformat(pix_fmt)) {
+		colour_description_present_flag = 1;
+		video_signal_type_present_flag = 1;
+		primaries = MSM_VIDC_PRIMARIES_BT709;
+		matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709;
+		transfer_char = MSM_VIDC_TRANSFER_BT709;
+		full_range = 0;
+	}
+
+	if (pixmp->quantization !=
+	    V4L2_QUANTIZATION_DEFAULT) {
+		video_signal_type_present_flag = 1;
+		full_range = pixmp->quantization ==
+			V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
+	}
+
+	payload = (matrix_coeff & 0xFF) |
+		((transfer_char << 8) & 0xFF00) |
+		((primaries << 16) & 0xFF0000) |
+		((colour_description_present_flag << 24) & 0x1000000) |
+		((full_range << 25) & 0x2000000) |
+		((video_format << 26) & 0x1C000000) |
+		((video_signal_type_present_flag << 29) & 0x20000000);
+	i_vpr_h(inst, "%s: color info: %#x\n", __func__, payload);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_SIGNAL_COLOR_INFO,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_32_PACKED,
+					&payload,
+					sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_quality_mode(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = inst->core;
+	u32 mode;
+
+	rc = call_session_op(core, decide_quality_mode, inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: decide_work_route failed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mode = inst->capabilities[QUALITY_MODE].value;
+	i_vpr_h(inst, "%s: quality_mode: %u\n", __func__, mode);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_QUALITY_MODE,
+					HFI_HOST_FLAGS_NONE,
+					HFI_PORT_BITSTREAM,
+					HFI_PAYLOAD_U32_ENUM,
+					&mode,
+					sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_ring_buffer_count(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_inst_cap *cap;
+
+	cap = &inst->capabilities[ENC_RING_BUFFER_COUNT];
+
+	if (!cap->set)
+		return 0;
+
+	rc = cap->set(inst, ENC_RING_BUFFER_COUNT);
+	if (rc) {
+		i_vpr_e(inst, "%s: set cap failed\n", __func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int msm_venc_set_input_properties(struct msm_vidc_inst *inst)
+{
+	int i, j, rc = 0;
+	static const struct msm_venc_prop_type_handle prop_type_handle_arr[] = {
+		{HFI_PROP_COLOR_FORMAT,               msm_venc_set_colorformat                 },
+		{HFI_PROP_RAW_RESOLUTION,             msm_venc_set_raw_resolution              },
+		{HFI_PROP_CROP_OFFSETS,               msm_venc_set_crop_offsets                },
+		{HFI_PROP_LINEAR_STRIDE_SCANLINE,     msm_venc_set_stride_scanline             },
+		{HFI_PROP_SIGNAL_COLOR_INFO,          msm_venc_set_colorspace                  },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_input_set_prop); i++) {
+		/* set session input properties */
+		for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
+			if (prop_type_handle_arr[j].type == msm_venc_input_set_prop[i]) {
+				rc = prop_type_handle_arr[j].handle(inst, INPUT_PORT);
+				if (rc)
+					goto exit;
+				break;
+			}
+		}
+
+		/* is property type unknown ? */
+		if (j == ARRAY_SIZE(prop_type_handle_arr))
+			i_vpr_e(inst, "%s: unknown property %#x\n", __func__,
+				msm_venc_input_set_prop[i]);
+	}
+
+exit:
+	return rc;
+}
+
+static int msm_venc_set_output_properties(struct msm_vidc_inst *inst)
+{
+	int i, j, rc = 0;
+	static const struct msm_venc_prop_type_handle prop_type_handle_arr[] = {
+		{HFI_PROP_BITSTREAM_RESOLUTION,       msm_venc_set_bitstream_resolution    },
+		{HFI_PROP_CROP_OFFSETS,               msm_venc_set_crop_offsets            },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_output_set_prop); i++) {
+		/* set session output properties */
+		for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
+			if (prop_type_handle_arr[j].type == msm_venc_output_set_prop[i]) {
+				rc = prop_type_handle_arr[j].handle(inst, OUTPUT_PORT);
+				if (rc)
+					goto exit;
+				break;
+			}
+		}
+
+		/* is property type unknown ? */
+		if (j == ARRAY_SIZE(prop_type_handle_arr))
+			i_vpr_e(inst, "%s: unknown property %#x\n", __func__,
+				msm_venc_output_set_prop[i]);
+	}
+
+exit:
+	return rc;
+}
+
+static int msm_venc_set_internal_properties(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_venc_set_quality_mode(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_venc_set_ring_buffer_count(inst);
+
+	return rc;
+}
+
+static int msm_venc_get_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) {
+		rc = msm_vidc_get_internal_buffers(inst, msm_venc_input_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_venc_destroy_internal_buffers(struct msm_vidc_inst *inst,
+					     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf, *dummy;
+	const u32 *internal_buf_type;
+	u32 i, len;
+
+	if (port == INPUT_PORT) {
+		internal_buf_type = msm_venc_input_internal_buffer_type;
+		len = ARRAY_SIZE(msm_venc_input_internal_buffer_type);
+	} else {
+		internal_buf_type = msm_venc_output_internal_buffer_type;
+		len = ARRAY_SIZE(msm_venc_output_internal_buffer_type);
+	}
+
+	for (i = 0; i < len; i++) {
+		buffers = msm_vidc_get_buffers(inst, internal_buf_type[i], __func__);
+		if (!buffers)
+			return -EINVAL;
+
+		if (buffers->reuse) {
+			i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__,
+				buf_name(internal_buf_type[i]));
+			continue;
+		}
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			i_vpr_h(inst,
+				"%s: destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n",
+				__func__, buf->type, buf->index, buf->fd,
+				buf->device_addr, buf->buffer_size);
+
+			rc = msm_vidc_destroy_internal_buffer(inst, buf);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int msm_venc_create_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) {
+		rc = msm_vidc_create_internal_buffers(inst, msm_venc_input_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_venc_queue_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) {
+		rc = msm_vidc_queue_internal_buffers(inst, msm_venc_input_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_venc_get_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) {
+		rc = msm_vidc_get_internal_buffers(inst, msm_venc_output_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_venc_create_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) {
+		rc = msm_vidc_create_internal_buffers(inst,
+						      msm_venc_output_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int msm_venc_queue_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) {
+		rc = msm_vidc_queue_internal_buffers(inst, msm_venc_output_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int msm_venc_property_subscription(struct msm_vidc_inst *inst,
+					  enum msm_vidc_port_type port)
+{
+	u32 payload[32] = {0};
+	u32 i;
+	u32 payload_size = 0;
+
+	payload[0] = HFI_MODE_PROPERTY;
+	if (port == INPUT_PORT) {
+		for (i = 0; i < ARRAY_SIZE(msm_venc_input_subscribe_for_properties); i++)
+			payload[i + 1] = msm_venc_input_subscribe_for_properties[i];
+		payload_size = (ARRAY_SIZE(msm_venc_input_subscribe_for_properties) + 1) *
+				sizeof(u32);
+	} else if (port == OUTPUT_PORT) {
+		for (i = 0; i < ARRAY_SIZE(msm_venc_output_subscribe_for_properties); i++)
+			payload[i + 1] = msm_venc_output_subscribe_for_properties[i];
+		payload_size = (ARRAY_SIZE(msm_venc_output_subscribe_for_properties) + 1) *
+				sizeof(u32);
+	} else {
+		i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	return venus_hfi_session_command(inst,
+				       HFI_CMD_SUBSCRIBE_MODE,
+				       port,
+				       HFI_PAYLOAD_U32_ARRAY,
+				       &payload[0],
+				       payload_size);
+}
+
+int msm_venc_streamoff_input(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_session_streamoff(inst, INPUT_PORT);
+}
+
+int msm_venc_streamon_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_check_session_supported(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_check_scaling_supported(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_set_input_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_get_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_destroy_internal_buffers(inst, INPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_create_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_queue_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_property_subscription(inst, INPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_process_streamon_input(inst);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	i_vpr_e(inst, "%s: failed\n", __func__);
+	return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
+{
+	return msm_vidc_queue_buffer_single(inst, vb2);
+}
+
+int msm_venc_stop_cmd(struct msm_vidc_inst *inst)
+{
+	i_vpr_h(inst, "received cmd: drain\n");
+	return msm_vidc_process_drain(inst);
+}
+
+int msm_venc_start_cmd(struct msm_vidc_inst *inst)
+{
+	i_vpr_h(inst, "received cmd: resume\n");
+
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
+
+	/* tune power features */
+	msm_vidc_allow_dcvs(inst);
+	msm_vidc_power_data_reset(inst);
+
+	/* print final buffer counts & size details */
+	msm_vidc_print_buffer_info(inst);
+
+	/* print internal buffer memory usage stats */
+	msm_vidc_print_memory_stats(inst);
+
+	return msm_vidc_process_resume(inst);
+}
+
+int msm_venc_streamoff_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	/* restore LAYER_COUNT max allowed value */
+	inst->capabilities[ENH_LAYER_COUNT].max =
+		core->capabilities[MAX_ENH_LAYER_COUNT].value;
+
+	rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_venc_streamon_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_venc_set_output_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_set_v4l2_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_set_internal_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_get_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_destroy_internal_buffers(inst, OUTPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_create_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_queue_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_property_subscription(inst, OUTPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_process_streamon_output(inst);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	i_vpr_e(inst, "%s: failed\n", __func__);
+	msm_venc_streamoff_output(inst);
+	return rc;
+}
+
+int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+	u32 pix_fmt;
+
+	memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
+
+	if (f->type == INPUT_MPLANE) {
+		pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+		if (!pix_fmt) {
+			i_vpr_e(inst, "%s: unsupported format, set current params\n", __func__);
+			f->fmt.pix_mp.pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat;
+			f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+			pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat,
+							     __func__);
+		}
+	} else if (f->type == OUTPUT_MPLANE) {
+		pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+		if (!pix_fmt) {
+			i_vpr_e(inst, "%s: unsupported codec, set current params\n", __func__);
+			f->fmt.pix_mp.width = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height;
+			f->fmt.pix_mp.pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type);
+		return -EINVAL;
+	}
+
+	if (pixmp->field == V4L2_FIELD_ANY)
+		pixmp->field = V4L2_FIELD_NONE;
+	pixmp->num_planes = 1;
+
+	return rc;
+}
+
+int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	struct v4l2_format *fmt;
+	struct msm_vidc_core *core;
+	u32 codec_align;
+	u32 width, height;
+	enum msm_vidc_codec_type codec;
+
+	core = inst->core;
+	msm_venc_try_fmt(inst, f);
+
+	fmt = &inst->fmts[OUTPUT_PORT];
+	if (fmt->fmt.pix_mp.pixelformat != f->fmt.pix_mp.pixelformat) {
+		rc = msm_venc_codec_change(inst, f->fmt.pix_mp.pixelformat);
+		if (rc)
+			return rc;
+	}
+	fmt->type = OUTPUT_MPLANE;
+
+	codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+
+	codec_align = (codec == MSM_VIDC_HEVC) ? 32 : 16;
+	/* use rotated width height if rotation is enabled */
+	width = inst->compose.width;
+	height = inst->compose.height;
+	if (is_rotation_90_or_270(inst)) {
+		width = inst->compose.height;
+		height = inst->compose.width;
+	}
+	/* width, height is readonly for client */
+	fmt->fmt.pix_mp.width = ALIGN(width, codec_align);
+	fmt->fmt.pix_mp.height = ALIGN(height, codec_align);
+	fmt->fmt.pix_mp.num_planes = 1;
+	fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+	fmt->fmt.pix_mp.plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
+	/* video hw supports conversion to V4L2_COLORSPACE_REC709 only */
+	if (f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT &&
+	    f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_REC709)
+		f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+	fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+	fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+	fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+	inst->buffers.output.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_OUTPUT);
+	if (inst->buffers.output.actual_count <
+		inst->buffers.output.min_count +
+		inst->buffers.output.extra_count) {
+		inst->buffers.output.actual_count =
+			inst->buffers.output.min_count +
+			inst->buffers.output.extra_count;
+	}
+	inst->buffers.output.size =
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	i_vpr_h(inst,
+		"%s: type: OUTPUT, codec %s width %d height %d size %u min_count %d extra_count %d\n",
+		__func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat),
+		fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height,
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
+		inst->buffers.output.min_count,
+		inst->buffers.output.extra_count);
+
+	/* finally update client format */
+	memcpy(f, fmt, sizeof(struct v4l2_format));
+	return rc;
+}
+
+static int msm_venc_s_fmt_input(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	struct v4l2_format *fmt, *output_fmt;
+	struct msm_vidc_core *core;
+	u32 pix_fmt, width, height, size, bytesperline;
+
+	core = inst->core;
+	msm_venc_try_fmt(inst, f);
+
+	pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+	msm_vidc_update_cap_value(inst, PIX_FMTS, pix_fmt, __func__);
+
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	if (is_rgba_colorformat(pix_fmt))
+		bytesperline = video_rgb_stride_bytes(pix_fmt, f->fmt.pix_mp.width);
+	else
+		bytesperline = video_y_stride_bytes(pix_fmt, f->fmt.pix_mp.width);
+
+	fmt = &inst->fmts[INPUT_PORT];
+	fmt->type = INPUT_MPLANE;
+	fmt->fmt.pix_mp.width = width;
+	fmt->fmt.pix_mp.height = height;
+	fmt->fmt.pix_mp.num_planes = 1;
+	fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
+	fmt->fmt.pix_mp.plane_fmt[0].bytesperline = bytesperline;
+	size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT);
+	fmt->fmt.pix_mp.plane_fmt[0].sizeimage = size;
+	/* update input port colorspace info */
+	fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+	fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+	fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+	fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+	/*
+	 * Update output port colorspace info.
+	 */
+	output_fmt = &inst->fmts[OUTPUT_PORT];
+	output_fmt->fmt.pix_mp.colorspace = fmt->fmt.pix_mp.colorspace;
+	output_fmt->fmt.pix_mp.xfer_func = fmt->fmt.pix_mp.xfer_func;
+	output_fmt->fmt.pix_mp.ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc;
+	output_fmt->fmt.pix_mp.quantization = fmt->fmt.pix_mp.quantization;
+
+	inst->buffers.input.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_INPUT);
+	inst->buffers.input.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_INPUT);
+	if (inst->buffers.input.actual_count <
+	    inst->buffers.input.min_count +
+	    inst->buffers.input.extra_count) {
+		inst->buffers.input.actual_count =
+			inst->buffers.input.min_count +
+			inst->buffers.input.extra_count;
+	}
+	inst->buffers.input.size = size;
+
+	if (f->fmt.pix_mp.width != inst->crop.width ||
+	    f->fmt.pix_mp.height != inst->crop.height) {
+		/* reset crop dimensions with updated resolution */
+		inst->crop.top = 0;
+		inst->crop.left = 0;
+		inst->crop.width = f->fmt.pix_mp.width;
+		inst->crop.height = f->fmt.pix_mp.height;
+
+		/* reset compose dimensions with updated resolution */
+		inst->compose.top = 0;
+		inst->compose.left = 0;
+		inst->compose.width = f->fmt.pix_mp.width;
+		inst->compose.height = f->fmt.pix_mp.height;
+
+		/* update output format */
+		rc = msm_venc_s_fmt_output(inst, output_fmt);
+		if (rc)
+			return rc;
+	}
+
+	i_vpr_h(inst,
+		"%s: type: INPUT, format %s width %d height %d size %u min_count %d extra_count %d\n",
+		__func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat),
+		fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height,
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
+		inst->buffers.input.min_count,
+		inst->buffers.input.extra_count);
+
+	/* finally update client format */
+	memcpy(f, fmt, sizeof(struct v4l2_format));
+
+	return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+
+	if (f->type == INPUT_MPLANE) {
+		rc = msm_venc_s_fmt_input(inst, f);
+		if (rc)
+			goto exit;
+	} else if (f->type == OUTPUT_MPLANE) {
+		rc = msm_venc_s_fmt_output(inst, f);
+		if (rc)
+			goto exit;
+	} else {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	if (rc)
+		i_vpr_e(inst, "%s: failed\n", __func__);
+
+	return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, f->type, __func__);
+	if (port < 0)
+		return -EINVAL;
+
+	memcpy(f, &inst->fmts[port], sizeof(struct v4l2_format));
+
+	return rc;
+}
+
+int msm_venc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	int rc = 0;
+	struct v4l2_format *output_fmt;
+
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (s->r.left || s->r.top) {
+			i_vpr_h(inst, "%s: unsupported top %d or left %d\n",
+				__func__, s->r.left, s->r.top);
+			s->r.left = 0;
+			s->r.top = 0;
+		}
+		if (s->r.width > inst->fmts[INPUT_PORT].fmt.pix_mp.width) {
+			i_vpr_h(inst, "%s: unsupported width %d, fmt width %d\n",
+				__func__, s->r.width,
+				inst->fmts[INPUT_PORT].fmt.pix_mp.width);
+			s->r.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+		}
+		if (s->r.height > inst->fmts[INPUT_PORT].fmt.pix_mp.height) {
+			i_vpr_h(inst, "%s: unsupported height %d, fmt height %d\n",
+				__func__, s->r.height,
+				inst->fmts[INPUT_PORT].fmt.pix_mp.height);
+			s->r.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+		}
+
+		inst->crop.left = s->r.left;
+		inst->crop.top = s->r.top;
+		inst->crop.width = s->r.width;
+		inst->crop.height = s->r.height;
+		/* adjust compose such that it is within crop */
+		inst->compose.left = inst->crop.left;
+		inst->compose.top = inst->crop.top;
+		inst->compose.width = inst->crop.width;
+		inst->compose.height = inst->crop.height;
+		/* update output format based on new crop dimensions */
+		output_fmt = &inst->fmts[OUTPUT_PORT];
+		rc = msm_venc_s_fmt_output(inst, output_fmt);
+		if (rc)
+			return rc;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->r.left < inst->crop.left) {
+			i_vpr_e(inst,
+				"%s: compose left (%d) less than crop left (%d)\n",
+				__func__, s->r.left, inst->crop.left);
+			s->r.left = inst->crop.left;
+		}
+		if (s->r.top < inst->crop.top) {
+			i_vpr_e(inst,
+				"%s: compose top (%d) less than crop top (%d)\n",
+				__func__, s->r.top, inst->crop.top);
+			s->r.top = inst->crop.top;
+		}
+		if (s->r.width > inst->crop.width) {
+			i_vpr_e(inst,
+				"%s: compose width (%d) greate than crop width (%d)\n",
+				__func__, s->r.width, inst->crop.width);
+			s->r.width = inst->crop.width;
+		}
+		if (s->r.height > inst->crop.height) {
+			i_vpr_e(inst,
+				"%s: compose height (%d) greate than crop height (%d)\n",
+				__func__, s->r.height, inst->crop.height);
+			s->r.height = inst->crop.height;
+		}
+		inst->compose.left = s->r.left;
+		inst->compose.top = s->r.top;
+		inst->compose.width = s->r.width;
+		inst->compose.height = s->r.height;
+
+		if (is_scaling_enabled(inst)) {
+			i_vpr_h(inst,
+				"%s: scaling enabled, crop: l %d t %d w %d h %d compose: l %d t %d w %d h %d\n",
+				__func__, inst->crop.left, inst->crop.top,
+				inst->crop.width, inst->crop.height,
+				inst->compose.left, inst->compose.top,
+				inst->compose.width, inst->compose.height);
+		}
+
+		/* update output format based on new compose dimensions */
+		output_fmt = &inst->fmts[OUTPUT_PORT];
+		rc = msm_venc_s_fmt_output(inst, output_fmt);
+		if (rc)
+			return rc;
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid target %d\n",
+			__func__, s->target);
+		rc = -EINVAL;
+		break;
+	}
+	if (!rc)
+		i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n",
+			__func__, s->target, s->r.top, s->r.left,
+			s->r.width, s->r.height);
+	return rc;
+}
+
+int msm_venc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	int rc = 0;
+
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = inst->crop.left;
+		s->r.top = inst->crop.top;
+		s->r.width = inst->crop.width;
+		s->r.height = inst->crop.height;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		s->r.left = inst->compose.left;
+		s->r.top = inst->compose.top;
+		s->r.width = inst->compose.width;
+		s->r.height = inst->compose.height;
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid target %d\n",
+			__func__, s->target);
+		rc = -EINVAL;
+		break;
+	}
+	if (!rc)
+		i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n",
+			__func__, s->target, s->r.top, s->r.left,
+			s->r.width, s->r.height);
+	return rc;
+}
+
+int msm_venc_s_param(struct msm_vidc_inst *inst,
+		     struct v4l2_streamparm *s_parm)
+{
+	int rc = 0;
+	struct v4l2_fract *timeperframe = NULL;
+	u32 q16_rate, max_rate, default_rate;
+	u64 us_per_frame = 0, input_rate = 0;
+	bool is_frame_rate = false;
+
+	if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		timeperframe = &s_parm->parm.output.timeperframe;
+		max_rate = inst->capabilities[OPERATING_RATE].max >> 16;
+		default_rate = inst->capabilities[OPERATING_RATE].value >> 16;
+		s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
+		timeperframe = &s_parm->parm.capture.timeperframe;
+		is_frame_rate = true;
+		max_rate = inst->capabilities[FRAME_RATE].max >> 16;
+		default_rate = inst->capabilities[FRAME_RATE].value >> 16;
+		s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	}
+
+	if (!timeperframe->denominator || !timeperframe->numerator) {
+		i_vpr_e(inst, "%s: type %s, invalid rate, update with default\n",
+			__func__, v4l2_type_name(s_parm->type));
+		if (!timeperframe->numerator)
+			timeperframe->numerator = 1;
+		if (!timeperframe->denominator)
+			timeperframe->denominator = default_rate;
+	}
+
+	us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
+	do_div(us_per_frame, timeperframe->denominator);
+
+	if (!us_per_frame) {
+		i_vpr_e(inst, "%s: us_per_frame is zero\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	input_rate = (u64)USEC_PER_SEC;
+	do_div(input_rate, us_per_frame);
+
+	i_vpr_h(inst, "%s: type %s, %s value %llu\n",
+		__func__, v4l2_type_name(s_parm->type),
+		is_frame_rate ? "frame rate" : "operating rate", input_rate);
+
+	q16_rate = (u32)input_rate << 16;
+	msm_vidc_update_cap_value(inst, is_frame_rate ? FRAME_RATE : OPERATING_RATE,
+				  q16_rate, __func__);
+	if ((s_parm->type == INPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming) ||
+	    (s_parm->type == OUTPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming)) {
+		rc = msm_vidc_check_core_mbps(inst);
+		if (rc) {
+			i_vpr_e(inst, "%s: unsupported load\n", __func__);
+			goto reset_rate;
+		}
+		rc = input_rate > max_rate;
+		if (rc) {
+			i_vpr_e(inst, "%s: unsupported rate %llu, max %u\n", __func__,
+				input_rate, max_rate);
+			rc = -ENOMEM;
+			goto reset_rate;
+		}
+	}
+
+	if (is_frame_rate)
+		inst->capabilities[FRAME_RATE].flags |= CAP_FLAG_CLIENT_SET;
+	else
+		inst->capabilities[OPERATING_RATE].flags |= CAP_FLAG_CLIENT_SET;
+	/*
+	 * In static case, frame rate is set via
+	 * inst database set function mentioned in
+	 * FRAME_RATE cap id.
+	 * In dynamic case, frame rate is set like below.
+	 */
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		rc = venus_hfi_session_property(inst,
+						HFI_PROP_FRAME_RATE,
+						HFI_HOST_FLAGS_NONE,
+						HFI_PORT_BITSTREAM,
+						HFI_PAYLOAD_Q16,
+						&q16_rate,
+						sizeof(u32));
+		if (rc) {
+			i_vpr_e(inst,
+				"%s: failed to set frame rate to fw\n", __func__);
+			goto exit;
+		}
+	}
+
+	return 0;
+
+reset_rate:
+	if (rc) {
+		i_vpr_e(inst, "%s: setting rate %llu failed, reset to %u\n", __func__,
+			input_rate, default_rate);
+		msm_vidc_update_cap_value(inst, is_frame_rate ? FRAME_RATE : OPERATING_RATE,
+					  default_rate << 16, __func__);
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_g_param(struct msm_vidc_inst *inst,
+		     struct v4l2_streamparm *s_parm)
+{
+	struct v4l2_fract *timeperframe = NULL;
+
+	if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		timeperframe = &s_parm->parm.output.timeperframe;
+		timeperframe->numerator = 1;
+		timeperframe->denominator =
+			inst->capabilities[OPERATING_RATE].value >> 16;
+		s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
+		timeperframe = &s_parm->parm.capture.timeperframe;
+		timeperframe->numerator = 1;
+		timeperframe->denominator =
+			inst->capabilities[FRAME_RATE].value >> 16;
+		s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	}
+
+	i_vpr_h(inst, "%s: type %s, num %u denom %u\n",
+		__func__, v4l2_type_name(s_parm->type), timeperframe->numerator,
+		timeperframe->denominator);
+	return 0;
+}
+
+int msm_venc_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		rc = v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL);
+		break;
+	case V4L2_EVENT_CTRL:
+		rc = v4l2_ctrl_subscribe_event(&inst->fh, sub);
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid type %d id %d\n", __func__, sub->type, sub->id);
+		return -EINVAL;
+	}
+
+	if (rc)
+		i_vpr_e(inst, "%s: failed, type %d id %d\n",
+			__func__, sub->type, sub->id);
+	return rc;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 array[32] = {0};
+	u32 i = 0;
+
+	core = inst->core;
+
+	if (f->type == OUTPUT_MPLANE) {
+		u32 codecs = core->capabilities[ENC_CODECS].value;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (codecs & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				array[idx] = codecs & BIT(i);
+				idx++;
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_codec_from_driver(inst, array[f->index],
+							__func__);
+		if (!f->pixelformat)
+			return -EINVAL;
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+		strscpy(f->description, "codec", sizeof(f->description));
+	} else if (f->type == INPUT_MPLANE) {
+		u32 formats = inst->capabilities[PIX_FMTS].step_or_mask;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (formats & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				array[idx] = formats & BIT(i);
+				idx++;
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_colorformat_from_driver(inst, array[f->index],
+							      __func__);
+		if (!f->pixelformat)
+			return -EINVAL;
+		strscpy(f->description, "colorformat", sizeof(f->description));
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+
+	i_vpr_h(inst, "%s: index %d, %s: %s, flags %#x\n",
+		__func__, f->index, f->description,
+		v4l2_pixelfmt_name(inst, f->pixelformat), f->flags);
+	return rc;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct v4l2_format *f;
+	enum msm_vidc_colorformat_type colorformat;
+
+	core = inst->core;
+
+	if (core->capabilities[DCVS].value)
+		inst->power.dcvs_mode = true;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	f->type = OUTPUT_MPLANE;
+	f->fmt.pix_mp.width = DEFAULT_WIDTH;
+	f->fmt.pix_mp.height = DEFAULT_HEIGHT;
+	f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+	f->fmt.pix_mp.plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.output.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.actual_count =
+			inst->buffers.output.min_count +
+			inst->buffers.output.extra_count;
+	inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->crop.left = 0;
+	inst->crop.top = 0;
+	inst->crop.width = f->fmt.pix_mp.width;
+	inst->crop.height = f->fmt.pix_mp.height;
+
+	inst->compose.left = 0;
+	inst->compose.top = 0;
+	inst->compose.width = f->fmt.pix_mp.width;
+	inst->compose.height = f->fmt.pix_mp.height;
+
+	f = &inst->fmts[INPUT_PORT];
+	f->type = INPUT_MPLANE;
+	f->fmt.pix_mp.pixelformat =
+		v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_NV12C, __func__);
+	f->fmt.pix_mp.width = DEFAULT_WIDTH;
+	f->fmt.pix_mp.height = DEFAULT_HEIGHT;
+	f->fmt.pix_mp.num_planes = 1;
+	colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat,
+						 __func__);
+	f->fmt.pix_mp.plane_fmt[0].bytesperline =
+		video_y_stride_bytes(colorformat, DEFAULT_WIDTH);
+	f->fmt.pix_mp.plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.input.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_INPUT);
+	inst->buffers.input.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_INPUT);
+	inst->buffers.input.actual_count =
+			inst->buffers.input.min_count +
+			inst->buffers.input.extra_count;
+	inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->hfi_rc_type = HFI_RC_VBR_CFR;
+	inst->hfi_layer_type = HFI_HIER_P_SLIDING_WINDOW;
+
+	rc = msm_venc_codec_change(inst,
+				   inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat);
+
+	return rc;
+}
+
+int msm_venc_inst_deinit(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_ctrl_handler_deinit(inst);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 08/33] iris: vidc: add video decoder files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (6 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 07/33] iris: iris: add video encoder files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:21   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 09/33] iris: vidc: add control files Vikash Garodia
                   ` (27 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements decoder functionalities of the driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/msm_vdec.h   |   40 +
 .../media/platform/qcom/iris/vidc/src/msm_vdec.c   | 2091 ++++++++++++++++++++
 2 files changed, 2131 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
new file mode 100644
index 0000000..bece9a2
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_inst.h"
+
+int msm_vdec_streamoff_input(struct msm_vidc_inst *inst);
+int msm_vdec_streamon_input(struct msm_vidc_inst *inst);
+int msm_vdec_streamoff_output(struct msm_vidc_inst *inst);
+int msm_vdec_streamon_output(struct msm_vidc_inst *inst);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
+int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vdec_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_vdec_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s);
+int msm_vdec_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub);
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_inst_deinit(struct msm_vidc_inst *inst);
+int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst);
+int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst);
+int msm_vdec_stop_cmd(struct msm_vidc_inst *inst);
+int msm_vdec_start_cmd(struct msm_vidc_inst *inst);
+int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst,
+				   struct msm_vidc_buffer *buf);
+int msm_vdec_set_num_comv(struct msm_vidc_inst *inst);
+int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst);
+int msm_vdec_create_input_internal_buffers(struct msm_vidc_inst *inst);
+int msm_vdec_queue_input_internal_buffers(struct msm_vidc_inst *inst);
+int msm_vdec_release_input_internal_buffers(struct msm_vidc_inst *inst);
+
+#endif // _MSM_VDEC_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
new file mode 100644
index 0000000..6f5bc29
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
@@ -0,0 +1,2091 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/v4l2-common.h>
+
+#include "hfi_packet.h"
+#include "msm_media_info.h"
+#include "msm_vdec.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "venus_hfi.h"
+
+/* TODO: update based on clips */
+#define MAX_DEC_BATCH_SIZE 6
+#define SKIP_BATCH_WINDOW 100
+
+static const u32 msm_vdec_internal_buffer_type[] = {
+	MSM_VIDC_BUF_BIN,
+	MSM_VIDC_BUF_COMV,
+	MSM_VIDC_BUF_NON_COMV,
+	MSM_VIDC_BUF_LINE,
+};
+
+static const u32 msm_vdec_output_internal_buffer_type[] = {
+	MSM_VIDC_BUF_DPB,
+};
+
+struct msm_vdec_prop_type_handle {
+	u32 type;
+	int (*handle)(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+};
+
+static int msm_vdec_codec_change(struct msm_vidc_inst *inst, u32 v4l2_codec)
+{
+	int rc = 0;
+	bool session_init = false;
+
+	if (!inst->codec)
+		session_init = true;
+
+	if (inst->codec && inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat == v4l2_codec)
+		return 0;
+
+	i_vpr_h(inst, "%s: codec changed from %s to %s\n",
+		__func__, v4l2_pixelfmt_name(inst, inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat),
+		v4l2_pixelfmt_name(inst, v4l2_codec));
+
+	inst->codec = v4l2_codec_to_driver(inst, v4l2_codec, __func__);
+	if (!inst->codec) {
+		i_vpr_e(inst, "%s: invalid codec %#x\n", __func__, v4l2_codec);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat = v4l2_codec;
+	rc = msm_vidc_update_debug_str(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_get_inst_capability(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_ctrl_handler_init(inst, session_init);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_update_buffer_count(inst, INPUT_PORT);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT);
+	if (rc)
+		goto exit;
+
+exit:
+	return rc;
+}
+
+static int msm_vdec_set_bitstream_resolution(struct msm_vidc_inst *inst,
+					     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 resolution;
+
+	resolution = inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 |
+		inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+	i_vpr_h(inst, "%s: width: %d height: %d\n", __func__,
+		inst->fmts[INPUT_PORT].fmt.pix_mp.width,
+		inst->fmts[INPUT_PORT].fmt.pix_mp.height);
+	inst->subcr_params[port].bitstream_resolution = resolution;
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_BITSTREAM_RESOLUTION,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32,
+					&resolution,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_linear_stride_scanline(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 stride_y, scanline_y, stride_uv, scanline_uv;
+	u32 payload[2];
+	enum msm_vidc_colorformat_type colorformat;
+
+	colorformat = v4l2_colorformat_to_driver(inst,
+						 inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
+						 __func__);
+
+	if (!is_linear_yuv_colorformat(colorformat))
+		return 0;
+
+	stride_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width;
+	scanline_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height;
+	stride_uv = stride_y;
+	scanline_uv = scanline_y / 2;
+
+	payload[0] = stride_y << 16 | scanline_y;
+	payload[1] = stride_uv << 16 | scanline_uv;
+	i_vpr_h(inst, "%s: stride_y: %d scanline_y: %d stride_uv: %d, scanline_uv: %d",
+		__func__, stride_y, scanline_y, stride_uv, scanline_uv);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_LINEAR_STRIDE_SCANLINE,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, OUTPUT_PORT),
+					HFI_PAYLOAD_U64,
+					&payload,
+					sizeof(u64));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_ubwc_stride_scanline(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 stride_y, scanline_y, stride_uv, scanline_uv;
+	u32 meta_stride_y, meta_scanline_y, meta_stride_uv, meta_scanline_uv;
+	u32 payload[4];
+	struct v4l2_format *f;
+	u32 pix_fmt, width, height, colorformat;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	pix_fmt = f->fmt.pix_mp.pixelformat;
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	colorformat = v4l2_colorformat_to_driver(inst, pix_fmt, __func__);
+
+	if (!is_ubwc_colorformat(colorformat))
+		return 0;
+
+	stride_y = video_y_stride_bytes(colorformat, width);
+	scanline_y = video_y_scanlines(colorformat, height);
+	stride_uv = video_uv_stride_bytes(colorformat, width);
+	scanline_uv = video_uv_scanlines(colorformat, height);
+
+	meta_stride_y = video_y_meta_stride(colorformat, width);
+	meta_scanline_y = video_y_meta_scanlines(colorformat, height);
+	meta_stride_uv = video_uv_meta_stride(colorformat, width);
+	meta_scanline_uv = video_uv_meta_scanlines(colorformat, height);
+
+	payload[0] = stride_y << 16 | scanline_y;
+	payload[1] = stride_uv << 16 | scanline_uv;
+	payload[2] = meta_stride_y << 16 | meta_scanline_y;
+	payload[3] = meta_stride_uv << 16 | meta_scanline_uv;
+
+	i_vpr_h(inst,
+		"%s: y: stride %d scanline %d, uv: stride %d scanline %d, y_meta: stride %d scaline %d, uv_meta: stride %d scanline %d",
+		__func__,
+		stride_y, scanline_y, stride_uv, scanline_uv,
+		meta_stride_y, meta_scanline_y,
+		meta_stride_uv, meta_scanline_uv);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_UBWC_STRIDE_SCANLINE,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, OUTPUT_PORT),
+					HFI_PAYLOAD_U32_ARRAY,
+					&payload[0],
+					sizeof(u32) * 4);
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_crop_offsets(struct msm_vidc_inst *inst,
+				     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 left_offset, top_offset, right_offset, bottom_offset;
+	u32 payload[2] = {0};
+
+	left_offset = inst->crop.left;
+	top_offset = inst->crop.top;
+	right_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.width -
+		inst->crop.width);
+	bottom_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.height -
+		inst->crop.height);
+
+	payload[0] = left_offset << 16 | top_offset;
+	payload[1] = right_offset << 16 | bottom_offset;
+	i_vpr_h(inst,
+		"%s: l_off: %d t_off: %d r_off: %d b_offs: %d",
+		__func__,
+		left_offset, top_offset, right_offset, bottom_offset);
+	inst->subcr_params[port].crop_offsets[0] = payload[0];
+	inst->subcr_params[port].crop_offsets[1] = payload[1];
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_CROP_OFFSETS,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_64_PACKED,
+					&payload,
+					sizeof(u64));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_bit_depth(struct msm_vidc_inst *inst,
+				  enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 pix_fmt;
+	u32 bitdepth = 8 << 16 | 8;
+	enum msm_vidc_colorformat_type colorformat;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	pix_fmt = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
+	colorformat = v4l2_colorformat_to_driver(inst, pix_fmt, __func__);
+	if (is_10bit_colorformat(colorformat))
+		bitdepth = 10 << 16 | 10;
+
+	inst->subcr_params[port].bit_depth = bitdepth;
+	msm_vidc_update_cap_value(inst, BIT_DEPTH, bitdepth, __func__);
+	i_vpr_h(inst, "%s: bit depth: %#x", __func__, bitdepth);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32,
+					&bitdepth,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_coded_frames(struct msm_vidc_inst *inst,
+				     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 coded_frames = 0;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	if (inst->capabilities[CODED_FRAMES].value ==
+			CODED_FRAMES_PROGRESSIVE)
+		coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
+	inst->subcr_params[port].coded_frames = coded_frames;
+	i_vpr_h(inst, "%s: coded frames: %d", __func__, coded_frames);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_CODED_FRAMES,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32,
+					&coded_frames,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_min_output_count(struct msm_vidc_inst *inst,
+					 enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 min_output;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	min_output = inst->buffers.output.min_count;
+	inst->subcr_params[port].fw_min_count = min_output;
+	i_vpr_h(inst, "%s: firmware min output count: %d",
+		__func__, min_output);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32,
+					&min_output,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+	return rc;
+}
+
+static int msm_vdec_set_picture_order_count(struct msm_vidc_inst *inst,
+					    enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 poc = 0;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	inst->subcr_params[port].pic_order_cnt = poc;
+	i_vpr_h(inst, "%s: picture order count: %d", __func__, poc);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_PIC_ORDER_CNT_TYPE,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32,
+					&poc,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_colorspace(struct msm_vidc_inst *inst,
+				   enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 primaries = MSM_VIDC_PRIMARIES_RESERVED;
+	u32 matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED;
+	u32 transfer_char = MSM_VIDC_TRANSFER_RESERVED;
+	u32 full_range = V4L2_QUANTIZATION_DEFAULT;
+	u32 colour_description_present_flag = 0;
+	u32 video_signal_type_present_flag = 0, color_info = 0;
+	/* Unspecified video format */
+	u32 video_format = 5;
+	struct v4l2_pix_format_mplane *pixmp = NULL;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	if (inst->codec == MSM_VIDC_VP9)
+		return 0;
+
+	pixmp = &inst->fmts[port].fmt.pix_mp;
+	if (pixmp->colorspace != V4L2_COLORSPACE_DEFAULT ||
+	    pixmp->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT ||
+	    pixmp->xfer_func != V4L2_XFER_FUNC_DEFAULT) {
+		colour_description_present_flag = 1;
+		video_signal_type_present_flag = 1;
+		primaries = v4l2_color_primaries_to_driver(inst,
+							   pixmp->colorspace, __func__);
+		matrix_coeff = v4l2_matrix_coeff_to_driver(inst,
+							   pixmp->ycbcr_enc, __func__);
+		transfer_char = v4l2_transfer_char_to_driver(inst,
+							     pixmp->xfer_func, __func__);
+	}
+
+	if (pixmp->quantization != V4L2_QUANTIZATION_DEFAULT) {
+		video_signal_type_present_flag = 1;
+		full_range = pixmp->quantization ==
+			V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
+	}
+
+	color_info = (matrix_coeff & 0xFF) |
+		((transfer_char << 8) & 0xFF00) |
+		((primaries << 16) & 0xFF0000) |
+		((colour_description_present_flag << 24) & 0x1000000) |
+		((full_range << 25) & 0x2000000) |
+		((video_format << 26) & 0x1C000000) |
+		((video_signal_type_present_flag << 29) & 0x20000000);
+
+	inst->subcr_params[port].color_info = color_info;
+	i_vpr_h(inst, "%s: color info: %#x\n", __func__, color_info);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_SIGNAL_COLOR_INFO,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_32_PACKED,
+					&color_info,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_profile(struct msm_vidc_inst *inst,
+				enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 profile;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	profile = inst->capabilities[PROFILE].value;
+	inst->subcr_params[port].profile = profile;
+	i_vpr_h(inst, "%s: profile: %d", __func__, profile);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_PROFILE,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32_ENUM,
+					&profile,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_level(struct msm_vidc_inst *inst,
+			      enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 level;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	level = inst->capabilities[LEVEL].value;
+	inst->subcr_params[port].level = level;
+	i_vpr_h(inst, "%s: level: %d", __func__, level);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_LEVEL,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32_ENUM,
+					&level,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_tier(struct msm_vidc_inst *inst,
+			     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 tier;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	tier = inst->capabilities[HEVC_TIER].value;
+	inst->subcr_params[port].tier = tier;
+	i_vpr_h(inst, "%s: tier: %d", __func__, tier);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_TIER,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, port),
+					HFI_PAYLOAD_U32_ENUM,
+					&tier,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_colorformat(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 pixelformat;
+	enum msm_vidc_colorformat_type colorformat;
+	u32 hfi_colorformat;
+
+	pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
+	colorformat = v4l2_colorformat_to_driver(inst, pixelformat, __func__);
+	hfi_colorformat = get_hfi_colorformat(inst, colorformat);
+	i_vpr_h(inst, "%s: hfi colorformat: %d",
+		__func__, hfi_colorformat);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_COLOR_FORMAT,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, OUTPUT_PORT),
+					HFI_PAYLOAD_U32,
+					&hfi_colorformat,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_set_output_properties(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vdec_set_colorformat(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_vdec_set_linear_stride_scanline(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_vdec_set_ubwc_stride_scanline(inst);
+
+	return rc;
+}
+
+int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
+		rc = msm_vidc_get_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_get_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_get_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+}
+
+static int msm_vdec_destroy_internal_buffers(struct msm_vidc_inst *inst,
+					     enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf, *dummy;
+	const u32 *internal_buf_type;
+	u32 i, len;
+
+	if (port == INPUT_PORT) {
+		internal_buf_type = msm_vdec_internal_buffer_type;
+		len = ARRAY_SIZE(msm_vdec_internal_buffer_type);
+	} else {
+		internal_buf_type = msm_vdec_output_internal_buffer_type;
+		len = ARRAY_SIZE(msm_vdec_output_internal_buffer_type);
+	}
+
+	for (i = 0; i < len; i++) {
+		buffers = msm_vidc_get_buffers(inst, internal_buf_type[i], __func__);
+		if (!buffers)
+			return -EINVAL;
+
+		if (buffers->reuse) {
+			i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__,
+				buf_name(internal_buf_type[i]));
+			continue;
+		}
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			i_vpr_h(inst,
+				"%s: destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n",
+				__func__, buf->type, buf->index, buf->fd,
+				buf->device_addr, buf->buffer_size);
+
+			rc = msm_vidc_destroy_internal_buffer(inst, buf);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+int msm_vdec_create_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
+		rc = msm_vidc_create_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int msm_vdec_create_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vdec_queue_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
+		rc = msm_vidc_queue_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int msm_vdec_queue_output_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vdec_release_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
+		rc = msm_vidc_release_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int msm_vdec_subscribe_input_port_settings_change(struct msm_vidc_inst *inst,
+							 enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 payload[32] = {0};
+	u32 i, j;
+	u32 subscribe_psc_size;
+	const u32 *psc;
+	static const struct msm_vdec_prop_type_handle prop_type_handle_arr[] = {
+		{HFI_PROP_BITSTREAM_RESOLUTION,          msm_vdec_set_bitstream_resolution   },
+		{HFI_PROP_CROP_OFFSETS,                  msm_vdec_set_crop_offsets           },
+		{HFI_PROP_LUMA_CHROMA_BIT_DEPTH,         msm_vdec_set_bit_depth              },
+		{HFI_PROP_CODED_FRAMES,                  msm_vdec_set_coded_frames           },
+		{HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,    msm_vdec_set_min_output_count       },
+		{HFI_PROP_PIC_ORDER_CNT_TYPE,            msm_vdec_set_picture_order_count    },
+		{HFI_PROP_SIGNAL_COLOR_INFO,             msm_vdec_set_colorspace             },
+		{HFI_PROP_PROFILE,                       msm_vdec_set_profile                },
+		{HFI_PROP_LEVEL,                         msm_vdec_set_level                  },
+		{HFI_PROP_TIER,                          msm_vdec_set_tier                   },
+	};
+
+	core = inst->core;
+
+	payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+	if (inst->codec == MSM_VIDC_H264) {
+		subscribe_psc_size = core->platform->data.psc_avc_tbl_size;
+		psc = core->platform->data.psc_avc_tbl;
+	} else if (inst->codec == MSM_VIDC_HEVC) {
+		subscribe_psc_size = core->platform->data.psc_hevc_tbl_size;
+		psc = core->platform->data.psc_hevc_tbl;
+	} else if (inst->codec == MSM_VIDC_VP9) {
+		subscribe_psc_size = core->platform->data.psc_vp9_tbl_size;
+		psc = core->platform->data.psc_vp9_tbl;
+	} else {
+		i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
+		psc = NULL;
+		return -EINVAL;
+	}
+
+	if (!psc || !subscribe_psc_size) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+	for (i = 0; i < subscribe_psc_size; i++)
+		payload[i + 1] = psc[i];
+	rc = venus_hfi_session_command(inst,
+				       HFI_CMD_SUBSCRIBE_MODE,
+				       port,
+				       HFI_PAYLOAD_U32_ARRAY,
+				       &payload[0],
+				       ((subscribe_psc_size + 1) *
+				       sizeof(u32)));
+
+	for (i = 0; i < subscribe_psc_size; i++) {
+		/* set session properties */
+		for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
+			if (prop_type_handle_arr[j].type == psc[i]) {
+				rc = prop_type_handle_arr[j].handle(inst, port);
+				if (rc)
+					goto exit;
+				break;
+			}
+		}
+
+		/* is property type unknown ? */
+		if (j == ARRAY_SIZE(prop_type_handle_arr))
+			i_vpr_e(inst, "%s: unknown property %#x\n", __func__, psc[i]);
+	}
+
+exit:
+	return rc;
+}
+
+static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
+				       enum msm_vidc_port_type port)
+{
+	u32 payload[32] = {0};
+	u32 i, count = 0;
+	struct msm_vidc_core *core;
+	u32 subscribe_prop_size;
+	const u32 *subcribe_prop;
+
+	core = inst->core;
+
+	payload[0] = HFI_MODE_PROPERTY;
+
+	if (port == INPUT_PORT) {
+		if (inst->codec == MSM_VIDC_H264) {
+			subscribe_prop_size = core->platform->data.dec_input_prop_size_avc;
+			subcribe_prop = core->platform->data.dec_input_prop_avc;
+		} else if (inst->codec == MSM_VIDC_HEVC) {
+			subscribe_prop_size = core->platform->data.dec_input_prop_size_hevc;
+			subcribe_prop = core->platform->data.dec_input_prop_hevc;
+		} else if (inst->codec == MSM_VIDC_VP9) {
+			subscribe_prop_size = core->platform->data.dec_input_prop_size_vp9;
+			subcribe_prop = core->platform->data.dec_input_prop_vp9;
+		} else {
+			i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
+			subcribe_prop = NULL;
+			return -EINVAL;
+		}
+
+		for (i = 0; i < subscribe_prop_size; i++) {
+			payload[count + 1] = subcribe_prop[i];
+			count++;
+
+			if (subcribe_prop[i] == HFI_PROP_DPB_LIST) {
+				inst->input_dpb_list_enabled = true;
+				i_vpr_h(inst, "%s: DPB_LIST suscribed on input port", __func__);
+			}
+		}
+	} else if (port == OUTPUT_PORT) {
+		if (inst->codec == MSM_VIDC_H264) {
+			subscribe_prop_size = core->platform->data.dec_output_prop_size_avc;
+			subcribe_prop = core->platform->data.dec_output_prop_avc;
+		} else if (inst->codec == MSM_VIDC_HEVC) {
+			subscribe_prop_size = core->platform->data.dec_output_prop_size_hevc;
+			subcribe_prop = core->platform->data.dec_output_prop_hevc;
+		} else if (inst->codec == MSM_VIDC_VP9) {
+			subscribe_prop_size = core->platform->data.dec_output_prop_size_vp9;
+			subcribe_prop = core->platform->data.dec_output_prop_vp9;
+		} else {
+			i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
+			subcribe_prop = NULL;
+			return -EINVAL;
+		}
+		for (i = 0; i < subscribe_prop_size; i++) {
+			payload[count + 1] = subcribe_prop[i];
+			count++;
+
+			if (subcribe_prop[i] == HFI_PROP_DPB_LIST) {
+				inst->output_dpb_list_enabled = true;
+				i_vpr_h(inst, "%s: DPB_LIST suscribed on output port", __func__);
+			}
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	return venus_hfi_session_command(inst,
+				       HFI_CMD_SUBSCRIBE_MODE,
+				       port,
+				       HFI_PAYLOAD_U32_ARRAY,
+				       &payload[0],
+				       (count + 1) * sizeof(u32));
+}
+
+int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_subscription_params *subsc_params;
+	u32 left_offset, top_offset, right_offset, bottom_offset;
+	u32 primaries, matrix_coeff, transfer_char;
+	u32 full_range = 0, video_format = 0;
+	u32 colour_description_present_flag = 0;
+	u32 video_signal_type_present_flag = 0;
+	struct v4l2_pix_format_mplane *pixmp_ip, *pixmp_op;
+
+	subsc_params = &inst->subcr_params[INPUT_PORT];
+	pixmp_ip = &inst->fmts[INPUT_PORT].fmt.pix_mp;
+	pixmp_op = &inst->fmts[OUTPUT_PORT].fmt.pix_mp;
+
+	subsc_params->bitstream_resolution =
+		pixmp_ip->width << 16 |
+		pixmp_ip->height;
+
+	left_offset = inst->crop.left;
+	top_offset = inst->crop.top;
+	right_offset = (pixmp_ip->width - inst->crop.width);
+	bottom_offset = (pixmp_ip->height - inst->crop.height);
+	subsc_params->crop_offsets[0] =
+			left_offset << 16 | top_offset;
+	subsc_params->crop_offsets[1] =
+			right_offset << 16 | bottom_offset;
+
+	subsc_params->fw_min_count = inst->buffers.output.min_count;
+
+	primaries = v4l2_color_primaries_to_driver(inst,
+						   pixmp_op->colorspace, __func__);
+	matrix_coeff = v4l2_matrix_coeff_to_driver(inst,
+						   pixmp_op->ycbcr_enc, __func__);
+	transfer_char = v4l2_transfer_char_to_driver(inst,
+						     pixmp_op->xfer_func, __func__);
+	full_range = pixmp_op->quantization ==
+		V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
+	subsc_params->color_info =
+		(matrix_coeff & 0xFF) |
+		((transfer_char << 8) & 0xFF00) |
+		((primaries << 16) & 0xFF0000) |
+		((colour_description_present_flag << 24) & 0x1000000) |
+		((full_range << 25) & 0x2000000) |
+		((video_format << 26) & 0x1C000000) |
+		((video_signal_type_present_flag << 29) & 0x20000000);
+
+	subsc_params->profile = inst->capabilities[PROFILE].value;
+	subsc_params->level = inst->capabilities[LEVEL].value;
+	subsc_params->tier = inst->capabilities[HEVC_TIER].value;
+	subsc_params->pic_order_cnt = inst->capabilities[POC].value;
+	subsc_params->bit_depth = inst->capabilities[BIT_DEPTH].value;
+	if (inst->capabilities[CODED_FRAMES].value ==
+			CODED_FRAMES_PROGRESSIVE)
+		subsc_params->coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
+	else
+		subsc_params->coded_frames = 0;
+
+	return 0;
+}
+
+int msm_vdec_set_num_comv(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 num_comv = 0;
+
+	num_comv = inst->capabilities[NUM_COMV].value;
+	i_vpr_h(inst, "%s: num COMV: %d", __func__, num_comv);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_COMV_BUFFER_COUNT,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, INPUT_PORT),
+					HFI_PAYLOAD_U32,
+					&num_comv,
+					sizeof(u32));
+	if (rc) {
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_read_input_subcr_params(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_subscription_params subsc_params;
+	struct msm_vidc_core *core;
+	u32 width, height;
+	u32 primaries, matrix_coeff, transfer_char;
+	u32 full_range = 0;
+	u32 colour_description_present_flag = 0;
+	u32 video_signal_type_present_flag = 0;
+	enum msm_vidc_colorformat_type output_fmt;
+	struct v4l2_pix_format_mplane *pixmp_ip, *pixmp_op;
+
+	core = inst->core;
+
+	subsc_params = inst->subcr_params[INPUT_PORT];
+	pixmp_ip = &inst->fmts[INPUT_PORT].fmt.pix_mp;
+	pixmp_op = &inst->fmts[OUTPUT_PORT].fmt.pix_mp;
+	width = (subsc_params.bitstream_resolution &
+		HFI_BITMASK_BITSTREAM_WIDTH) >> 16;
+	height = subsc_params.bitstream_resolution &
+		HFI_BITMASK_BITSTREAM_HEIGHT;
+
+	pixmp_ip->width = width;
+	pixmp_ip->height = height;
+
+	output_fmt = v4l2_colorformat_to_driver(inst,
+						pixmp_op->pixelformat, __func__);
+
+	pixmp_op->width = video_y_stride_pix(output_fmt, width);
+	pixmp_op->height = video_y_scanlines(output_fmt, height);
+	pixmp_op->plane_fmt[0].bytesperline =
+		video_y_stride_bytes(output_fmt, width);
+	pixmp_op->plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
+
+	matrix_coeff = subsc_params.color_info & 0xFF;
+	transfer_char = (subsc_params.color_info & 0xFF00) >> 8;
+	primaries = (subsc_params.color_info & 0xFF0000) >> 16;
+	colour_description_present_flag =
+		(subsc_params.color_info & 0x1000000) >> 24;
+	full_range = (subsc_params.color_info & 0x2000000) >> 25;
+	video_signal_type_present_flag =
+		(subsc_params.color_info & 0x20000000) >> 29;
+
+	pixmp_op->colorspace = V4L2_COLORSPACE_DEFAULT;
+	pixmp_op->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	pixmp_op->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	pixmp_op->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+	if (video_signal_type_present_flag) {
+		pixmp_op->quantization =
+			full_range ?
+			V4L2_QUANTIZATION_FULL_RANGE :
+			V4L2_QUANTIZATION_LIM_RANGE;
+		if (colour_description_present_flag) {
+			pixmp_op->colorspace =
+				v4l2_color_primaries_from_driver(inst, primaries, __func__);
+			pixmp_op->xfer_func =
+				v4l2_transfer_char_from_driver(inst, transfer_char, __func__);
+			pixmp_op->ycbcr_enc =
+				v4l2_matrix_coeff_from_driver(inst, matrix_coeff, __func__);
+		} else {
+			i_vpr_h(inst,
+				"%s: color description flag is not present\n",
+				__func__);
+		}
+	} else {
+		i_vpr_h(inst, "%s: video_signal type is not present\n",
+			__func__);
+	}
+
+	/* align input port color info with output port */
+	pixmp_ip->colorspace = pixmp_op->colorspace;
+	pixmp_ip->xfer_func = pixmp_op->xfer_func;
+	pixmp_ip->ycbcr_enc = pixmp_op->ycbcr_enc;
+	pixmp_ip->quantization = pixmp_op->quantization;
+
+	inst->crop.top = subsc_params.crop_offsets[0] & 0xFFFF;
+	inst->crop.left = (subsc_params.crop_offsets[0] >> 16) & 0xFFFF;
+	inst->crop.height = pixmp_ip->height -
+		(subsc_params.crop_offsets[1] & 0xFFFF) - inst->crop.top;
+	inst->crop.width = pixmp_ip->width -
+		((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left;
+
+	msm_vidc_update_cap_value(inst, PROFILE, subsc_params.profile, __func__);
+	msm_vidc_update_cap_value(inst, LEVEL, subsc_params.level, __func__);
+	msm_vidc_update_cap_value(inst, HEVC_TIER, subsc_params.tier, __func__);
+	msm_vidc_update_cap_value(inst, POC, subsc_params.pic_order_cnt, __func__);
+	if (subsc_params.bit_depth == BIT_DEPTH_8)
+		msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_8, __func__);
+	else
+		msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_10, __func__);
+	if (subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)
+		msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_PROGRESSIVE, __func__);
+	else
+		msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_INTERLACE, __func__);
+
+	inst->fw_min_count = subsc_params.fw_min_count;
+	inst->buffers.output.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_OUTPUT);
+
+	return 0;
+}
+
+int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst)
+{
+	u32 rc = 0;
+	struct v4l2_event event = {0};
+
+	if (!inst->bufq[INPUT_PORT].vb2q->streaming) {
+		i_vpr_e(inst, "%s: input port not streaming\n",
+			__func__);
+		return 0;
+	}
+
+	rc = msm_vdec_read_input_subcr_params(inst);
+	if (rc)
+		return rc;
+
+	event.type = V4L2_EVENT_SOURCE_CHANGE;
+	event.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION;
+	v4l2_event_queue_fh(&inst->fh, &event);
+
+	return rc;
+}
+
+int msm_vdec_streamoff_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_session_streamoff(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vdec_streamon_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_check_session_supported(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_set_v4l2_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_get_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_destroy_internal_buffers(inst, INPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_create_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_queue_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	if (!inst->ipsc_properties_set) {
+		rc = msm_vdec_subscribe_input_port_settings_change(inst, INPUT_PORT);
+		if (rc)
+			goto error;
+		inst->ipsc_properties_set = true;
+	}
+
+	rc = msm_vdec_subscribe_property(inst, INPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_process_streamon_input(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_flush_ts(inst);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	i_vpr_e(inst, "%s: failed\n", __func__);
+	return rc;
+}
+
+static int schedule_batch_work(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	mod_delayed_work(core->batch_workq, &inst->decode_batch.work,
+			 msecs_to_jiffies(core->capabilities[DECODE_BATCH_TIMEOUT].value));
+
+	return 0;
+}
+
+static int cancel_batch_work(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		d_vpr_e("%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+	cancel_delayed_work(&inst->decode_batch.work);
+
+	return 0;
+}
+
+int msm_vdec_streamoff_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	/* cancel pending batch work */
+	cancel_batch_work(inst);
+	rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int msm_vdec_subscribe_output_port_settings_change(struct msm_vidc_inst *inst,
+							  enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 payload[32] = {0};
+	u32 prop_type, payload_size, payload_type;
+	u32 i;
+	struct msm_vidc_subscription_params subsc_params;
+	u32 subscribe_psc_size = 0;
+	const u32 *psc = NULL;
+
+	core = inst->core;
+
+	payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+	if (inst->codec == MSM_VIDC_H264) {
+		subscribe_psc_size = core->platform->data.psc_avc_tbl_size;
+		psc = core->platform->data.psc_avc_tbl;
+	} else if (inst->codec == MSM_VIDC_HEVC) {
+		subscribe_psc_size = core->platform->data.psc_hevc_tbl_size;
+		psc = core->platform->data.psc_hevc_tbl;
+	} else if (inst->codec == MSM_VIDC_VP9) {
+		subscribe_psc_size = core->platform->data.psc_vp9_tbl_size;
+		psc = core->platform->data.psc_vp9_tbl;
+	} else {
+		i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
+		psc = NULL;
+		return -EINVAL;
+	}
+
+	if (!psc || !subscribe_psc_size) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+	for (i = 0; i < subscribe_psc_size; i++)
+		payload[i + 1] = psc[i];
+
+	rc = venus_hfi_session_command(inst,
+				       HFI_CMD_SUBSCRIBE_MODE,
+				       port,
+				       HFI_PAYLOAD_U32_ARRAY,
+				       &payload[0],
+				       ((subscribe_psc_size + 1) *
+				       sizeof(u32)));
+
+	subsc_params = inst->subcr_params[port];
+	for (i = 0; i < subscribe_psc_size; i++) {
+		payload[0] = 0;
+		payload[1] = 0;
+		payload_size = 0;
+		payload_type = 0;
+		prop_type = psc[i];
+		switch (prop_type) {
+		case HFI_PROP_BITSTREAM_RESOLUTION:
+			payload[0] = subsc_params.bitstream_resolution;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_CROP_OFFSETS:
+			payload[0] = subsc_params.crop_offsets[0];
+			payload[1] = subsc_params.crop_offsets[1];
+			payload_size = sizeof(u64);
+			payload_type = HFI_PAYLOAD_64_PACKED;
+			break;
+		case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
+			payload[0] = subsc_params.bit_depth;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_CODED_FRAMES:
+			payload[0] = subsc_params.coded_frames;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
+			payload[0] = subsc_params.fw_min_count;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_PIC_ORDER_CNT_TYPE:
+			payload[0] = subsc_params.pic_order_cnt;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_SIGNAL_COLOR_INFO:
+			payload[0] = subsc_params.color_info;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_PROFILE:
+			payload[0] = subsc_params.profile;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_LEVEL:
+			payload[0] = subsc_params.level;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		case HFI_PROP_TIER:
+			payload[0] = subsc_params.tier;
+			payload_size = sizeof(u32);
+			payload_type = HFI_PAYLOAD_U32;
+			break;
+		default:
+			i_vpr_e(inst, "%s: unknown property %#x\n", __func__,
+				prop_type);
+			prop_type = 0;
+			rc = -EINVAL;
+			break;
+		}
+		if (prop_type) {
+			rc = venus_hfi_session_property(inst,
+							prop_type,
+							HFI_HOST_FLAGS_NONE,
+							get_hfi_port(inst, port),
+							payload_type,
+							&payload,
+							payload_size);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return rc;
+}
+
+int msm_vdec_streamon_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (inst->capabilities[CODED_FRAMES].value == CODED_FRAMES_INTERLACE &&
+	    !is_ubwc_colorformat(inst->capabilities[PIX_FMTS].value)) {
+		i_vpr_e(inst,
+			"%s: interlace with non-ubwc color format is unsupported\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_check_session_supported(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_set_output_properties(inst);
+	if (rc)
+		goto error;
+
+	if (!inst->opsc_properties_set) {
+		memcpy(&inst->subcr_params[OUTPUT_PORT],
+		       &inst->subcr_params[INPUT_PORT],
+		       sizeof(inst->subcr_params[INPUT_PORT]));
+		rc = msm_vdec_subscribe_output_port_settings_change(inst, OUTPUT_PORT);
+		if (rc)
+			goto error;
+		inst->opsc_properties_set = true;
+	}
+
+	rc = msm_vdec_subscribe_property(inst, OUTPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_get_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_destroy_internal_buffers(inst, OUTPUT_PORT);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_create_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vidc_process_streamon_output(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_vdec_queue_output_internal_buffers(inst);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	i_vpr_e(inst, "%s: failed\n", __func__);
+	msm_vdec_streamoff_output(inst);
+	return rc;
+}
+
+static inline
+enum msm_vidc_allow msm_vdec_allow_queue_deferred_buffers(struct msm_vidc_inst *inst)
+{
+	int count;
+
+	/* do not defer buffers initially to avoid latency issues */
+	if (inst->power.buffer_counter <= SKIP_BATCH_WINDOW)
+		return MSM_VIDC_ALLOW;
+
+	/* defer qbuf, if pending buffers count less than batch size */
+	count = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_DEFERRED);
+	if (count < inst->decode_batch.size)
+		return MSM_VIDC_DEFER;
+
+	return MSM_VIDC_ALLOW;
+}
+
+static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst,
+			       struct vb2_buffer *vb2)
+{
+	struct msm_vidc_buffer *buf = NULL;
+	enum msm_vidc_allow allow;
+
+	if (!inst->decode_batch.size) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	buf = msm_vidc_get_driver_buf(inst, vb2);
+	if (!buf)
+		return -EINVAL;
+
+	if (is_state(inst, MSM_VIDC_OPEN) ||
+	    is_state(inst, MSM_VIDC_INPUT_STREAMING)) {
+		print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+		return 0;
+	}
+
+	allow = msm_vdec_allow_queue_deferred_buffers(inst);
+	if (allow == MSM_VIDC_DISALLOW) {
+		i_vpr_e(inst, "%s: queue deferred buffers not allowed\n", __func__);
+		return -EINVAL;
+	} else if (allow == MSM_VIDC_DEFER) {
+		print_vidc_buffer(VIDC_LOW, "low ", "batch-qbuf deferred", inst, buf);
+		schedule_batch_work(inst);
+		return 0;
+	}
+
+	cancel_batch_work(inst);
+	return msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT);
+}
+
+static int msm_vdec_release_eligible_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *ro_buf;
+
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		/* release only release eligible read-only buffers */
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_RELEASE_ELIGIBLE))
+			continue;
+		/* skip releasing buffers for which release cmd was already sent */
+		if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		rc = venus_hfi_release_buffer(inst, ro_buf);
+		if (rc)
+			return rc;
+		ro_buf->attr |= MSM_VIDC_ATTR_PENDING_RELEASE;
+		ro_buf->attr &= ~MSM_VIDC_ATTR_RELEASE_ELIGIBLE;
+		print_vidc_buffer(VIDC_LOW, "low ", "release buf", inst, ro_buf);
+	}
+
+	return rc;
+}
+
+static int msm_vdec_release_nonref_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 fw_ro_count = 0, nonref_ro_count = 0;
+	struct msm_vidc_buffer *ro_buf;
+	int i = 0;
+	bool found = false;
+
+	/* count read_only buffers which are not pending release in read_only list */
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY))
+			continue;
+		if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		fw_ro_count++;
+	}
+
+	if (fw_ro_count <= MAX_DPB_COUNT)
+		return 0;
+
+	/*
+	 * Mark those read only buffers present in read_only list as
+	 * non-reference if that buffer is not part of dpb_list_payload.
+	 * count such non-ref read only buffers as nonref_ro_count.
+	 * dpb_list_payload details:
+	 * payload[0-1]           : 64 bits base_address of DPB-1
+	 * payload[2]             : 32 bits addr_offset  of DPB-1
+	 * payload[3]             : 32 bits data_offset  of DPB-1
+	 */
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		found = false;
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY))
+			continue;
+		if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) {
+			if (ro_buf->device_addr == inst->dpb_list_payload[i] &&
+			    ro_buf->data_offset == inst->dpb_list_payload[i + 3]) {
+				found = true;
+				break;
+			}
+		}
+		if (!found)
+			nonref_ro_count++;
+	}
+
+	if (nonref_ro_count <= inst->buffers.output.min_count)
+		return 0;
+
+	i_vpr_l(inst, "%s: fw ro buf count %d, non-ref ro count %d\n",
+		__func__, fw_ro_count, nonref_ro_count);
+
+	/* release the eligible buffers as per above condition */
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		found = false;
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY))
+			continue;
+		if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) {
+			if (ro_buf->device_addr == inst->dpb_list_payload[i] &&
+			    ro_buf->data_offset == inst->dpb_list_payload[i + 3]) {
+				found = true;
+				break;
+			}
+		}
+		if (!found) {
+			ro_buf->attr |= MSM_VIDC_ATTR_PENDING_RELEASE;
+			print_vidc_buffer(VIDC_LOW, "low ", "release buf", inst, ro_buf);
+			rc = venus_hfi_release_buffer(inst, ro_buf);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
+{
+	int rc = 0;
+
+	/* batch decoder output & meta buffer only */
+	if (inst->decode_batch.enable && vb2->type == OUTPUT_MPLANE)
+		rc = msm_vdec_qbuf_batch(inst, vb2);
+	else
+		rc = msm_vidc_queue_buffer_single(inst, vb2);
+	if (rc)
+		return rc;
+
+	/*
+	 * if DPB_LIST property is subscribed on output port, then
+	 * driver needs to hold at least MAX_BPB_COUNT of read only
+	 * buffers. So call msm_vdec_release_nonref_buffers() to handle
+	 * the same.
+	 */
+	if (vb2->type == OUTPUT_MPLANE) {
+		if (inst->input_dpb_list_enabled)
+			rc = msm_vdec_release_eligible_buffers(inst);
+		else if (inst->output_dpb_list_enabled)
+			rc = msm_vdec_release_nonref_buffers(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vdec_alloc_and_queue_additional_dpb_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buffer = NULL;
+	int i, cur_min_count = 0, rc = 0;
+
+	/* get latest min_count and size */
+	rc = msm_vidc_get_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+
+	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_DPB, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	/* get current min_count */
+	list_for_each_entry(buffer, &buffers->list, list)
+		cur_min_count++;
+
+	/* skip alloc and queue */
+	if (cur_min_count >= buffers->min_count)
+		return 0;
+
+	i_vpr_h(inst, "%s: dpb buffer count increased from %u -> %u\n",
+		__func__, cur_min_count, buffers->min_count);
+
+	/* allocate additional DPB buffers */
+	for (i = cur_min_count; i < buffers->min_count; i++) {
+		rc = msm_vidc_create_internal_buffer(inst, MSM_VIDC_BUF_DPB, i);
+		if (rc)
+			return rc;
+	}
+
+	/* queue additional DPB buffers */
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vdec_stop_cmd(struct msm_vidc_inst *inst)
+{
+	i_vpr_h(inst, "received cmd: drain\n");
+	return msm_vidc_process_drain(inst);
+}
+
+int msm_vdec_start_cmd(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	i_vpr_h(inst, "received cmd: resume\n");
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
+
+	if (inst->capabilities[CODED_FRAMES].value == CODED_FRAMES_INTERLACE &&
+	    !is_ubwc_colorformat(inst->capabilities[PIX_FMTS].value)) {
+		i_vpr_e(inst,
+			"%s: interlace with non-ubwc color format is unsupported\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/* tune power features */
+	inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
+	msm_vidc_allow_dcvs(inst);
+	msm_vidc_power_data_reset(inst);
+
+	/*
+	 * client is completing partial port reconfiguration,
+	 * hence reallocate input internal buffers before input port
+	 * is resumed.
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC) &&
+	    is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) &&
+	    is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+		rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst);
+		if (rc)
+			return rc;
+
+		rc = msm_vidc_set_stage(inst, STAGE);
+		if (rc)
+			return rc;
+
+		rc = msm_vidc_set_pipe(inst, PIPE);
+		if (rc)
+			return rc;
+	}
+
+	/* allocate and queue extra dpb buffers */
+	rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst);
+	if (rc)
+		return rc;
+
+	/* queue pending deferred buffers */
+	rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT);
+	if (rc)
+		return rc;
+
+	/* print final buffer counts & size details */
+	msm_vidc_print_buffer_info(inst);
+
+	/* print internal buffer memory usage stats */
+	msm_vidc_print_memory_stats(inst);
+
+	rc = msm_vidc_process_resume(inst);
+
+	return rc;
+}
+
+int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+	u32 pix_fmt;
+
+	memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
+	if (f->type == INPUT_MPLANE) {
+		pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+		if (!pix_fmt) {
+			i_vpr_e(inst, "%s: unsupported codec, set current params\n", __func__);
+			f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+			f->fmt.pix_mp.pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat;
+			pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+		}
+	} else if (f->type == OUTPUT_MPLANE) {
+		pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+		if (!pix_fmt) {
+			i_vpr_e(inst, "%s: unsupported format, set current params\n", __func__);
+			f->fmt.pix_mp.pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
+			f->fmt.pix_mp.width = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height;
+		}
+		if (inst->bufq[INPUT_PORT].vb2q->streaming) {
+			f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+			f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type);
+		return -EINVAL;
+	}
+
+	if (pixmp->field == V4L2_FIELD_ANY)
+		pixmp->field = V4L2_FIELD_NONE;
+
+	pixmp->num_planes = 1;
+	return rc;
+}
+
+static bool msm_vidc_check_max_sessions_vp9d(struct msm_vidc_core *core)
+{
+	u32 vp9d_instance_count = 0;
+	struct msm_vidc_inst *inst = NULL;
+
+	core_lock(core, __func__);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (is_decode_session(inst) &&
+		    inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat ==
+			V4L2_PIX_FMT_VP9)
+			vp9d_instance_count++;
+	}
+	core_unlock(core, __func__);
+
+	if (vp9d_instance_count > MAX_VP9D_INST_COUNT)
+		return true;
+	return false;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct v4l2_format *fmt, *output_fmt;
+	u32 codec_align;
+	enum msm_vidc_colorformat_type colorformat;
+
+	core = inst->core;
+	msm_vdec_try_fmt(inst, f);
+
+	if (f->type == INPUT_MPLANE) {
+		if (inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat !=
+			f->fmt.pix_mp.pixelformat) {
+			rc = msm_vdec_codec_change(inst, f->fmt.pix_mp.pixelformat);
+			if (rc)
+				goto err_invalid_fmt;
+		}
+
+		if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP9) {
+			if (msm_vidc_check_max_sessions_vp9d(inst->core)) {
+				i_vpr_e(inst,
+					"%s: vp9d sessions exceeded max limit %d\n",
+					__func__, MAX_VP9D_INST_COUNT);
+				rc = -ENOMEM;
+				goto err_invalid_fmt;
+			}
+		}
+
+		fmt = &inst->fmts[INPUT_PORT];
+		fmt->type = INPUT_MPLANE;
+
+		codec_align = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat ==
+			V4L2_PIX_FMT_HEVC ? 32 : 16;
+		fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align);
+		fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align);
+		fmt->fmt.pix_mp.num_planes = 1;
+		fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage =
+			call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT);
+		inst->buffers.input.min_count =
+			call_session_op(core, min_count, inst, MSM_VIDC_BUF_INPUT);
+		inst->buffers.input.extra_count =
+			call_session_op(core, extra_count, inst, MSM_VIDC_BUF_INPUT);
+		if (inst->buffers.input.actual_count <
+			inst->buffers.input.min_count +
+			inst->buffers.input.extra_count) {
+			inst->buffers.input.actual_count =
+				inst->buffers.input.min_count +
+				inst->buffers.input.extra_count;
+		}
+		inst->buffers.input.size =
+			fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+		/* update input port color info */
+		fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+		fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+		fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+		fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+		/* update output port color info */
+		output_fmt = &inst->fmts[OUTPUT_PORT];
+		output_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+		output_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+		output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+		output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+
+		/* update crop dimensions */
+		inst->crop.left = 0;
+		inst->crop.top = 0;
+		inst->crop.width = f->fmt.pix_mp.width;
+		inst->crop.height = f->fmt.pix_mp.height;
+		i_vpr_h(inst,
+			"%s: type: INPUT, codec %s width %d height %d size %u min_count %d extra_count %d\n",
+			__func__, v4l2_pixelfmt_name(inst, f->fmt.pix_mp.pixelformat),
+			f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+			fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
+			inst->buffers.input.min_count,
+			inst->buffers.input.extra_count);
+	} else if (f->type == OUTPUT_MPLANE) {
+		fmt = &inst->fmts[OUTPUT_PORT];
+		fmt->type = OUTPUT_MPLANE;
+		if (inst->bufq[INPUT_PORT].vb2q->streaming) {
+			f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+			f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+		}
+		fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
+		colorformat = v4l2_colorformat_to_driver(inst, fmt->fmt.pix_mp.pixelformat,
+							 __func__);
+		fmt->fmt.pix_mp.width = video_y_stride_pix(colorformat, f->fmt.pix_mp.width);
+		fmt->fmt.pix_mp.height = video_y_scanlines(colorformat, f->fmt.pix_mp.height);
+		fmt->fmt.pix_mp.num_planes = 1;
+		fmt->fmt.pix_mp.plane_fmt[0].bytesperline =
+			video_y_stride_bytes(colorformat, f->fmt.pix_mp.width);
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage =
+			call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
+
+		if (!inst->bufq[INPUT_PORT].vb2q->streaming)
+			inst->buffers.output.min_count =
+				call_session_op(core, min_count, inst, MSM_VIDC_BUF_OUTPUT);
+		inst->buffers.output.extra_count =
+			call_session_op(core, extra_count, inst, MSM_VIDC_BUF_OUTPUT);
+		if (inst->buffers.output.actual_count <
+			inst->buffers.output.min_count +
+			inst->buffers.output.extra_count) {
+			inst->buffers.output.actual_count =
+				inst->buffers.output.min_count +
+				inst->buffers.output.extra_count;
+		}
+		inst->buffers.output.size =
+			fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+		msm_vidc_update_cap_value(inst, PIX_FMTS, colorformat, __func__);
+
+		/* update crop while input port is not streaming */
+		if (!inst->bufq[INPUT_PORT].vb2q->streaming) {
+			inst->crop.top = 0;
+			inst->crop.left = 0;
+			inst->crop.width = f->fmt.pix_mp.width;
+			inst->crop.height = f->fmt.pix_mp.height;
+		}
+		i_vpr_h(inst,
+			"%s: type: OUTPUT, format %s width %d height %d size %u min_count %d extra_count %d\n",
+			__func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat),
+			fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height,
+			fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
+			inst->buffers.output.min_count,
+			inst->buffers.output.extra_count);
+	} else {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type);
+		goto err_invalid_fmt;
+	}
+	memcpy(f, fmt, sizeof(struct v4l2_format));
+
+err_invalid_fmt:
+	return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	int rc = 0;
+	int port;
+
+	port = v4l2_type_to_driver_port(inst, f->type, __func__);
+	if (port < 0)
+		return -EINVAL;
+
+	memcpy(f, &inst->fmts[port], sizeof(struct v4l2_format));
+
+	return rc;
+}
+
+int msm_vdec_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	i_vpr_e(inst, "%s: unsupported\n", __func__);
+	return -EINVAL;
+}
+
+int msm_vdec_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s)
+{
+	if (s->type != OUTPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		s->r.left = inst->crop.left;
+		s->r.top = inst->crop.top;
+		s->r.width = inst->crop.width;
+		s->r.height = inst->crop.height;
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid target %d\n",
+			__func__, s->target);
+		return -EINVAL;
+	}
+	i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n",
+		__func__, s->target, s->r.top, s->r.left,
+		s->r.width, s->r.height);
+	return 0;
+}
+
+int msm_vdec_subscribe_event(struct msm_vidc_inst *inst,
+			     const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		rc = v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL);
+		break;
+	case V4L2_EVENT_SOURCE_CHANGE:
+		rc = v4l2_src_change_event_subscribe(&inst->fh, sub);
+		break;
+	case V4L2_EVENT_CTRL:
+		rc = v4l2_ctrl_subscribe_event(&inst->fh, sub);
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid type %d id %d\n", __func__, sub->type, sub->id);
+		return -EINVAL;
+	}
+
+	if (rc)
+		i_vpr_e(inst, "%s: failed, type %d id %d\n",
+			__func__, sub->type, sub->id);
+	return rc;
+}
+
+static int msm_vdec_check_colorformat_supported(struct msm_vidc_inst *inst,
+						enum msm_vidc_colorformat_type colorformat)
+{
+	bool supported = true;
+
+	/* do not reject coloformats before streamon */
+	if (!inst->bufq[INPUT_PORT].vb2q->streaming)
+		return true;
+
+	/*
+	 * bit_depth 8 bit supports 8 bit colorformats only
+	 * bit_depth 10 bit supports 10 bit colorformats only
+	 * interlace supports ubwc colorformats only
+	 */
+	if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_8 &&
+	    !is_8bit_colorformat(colorformat))
+		supported = false;
+	if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_10 &&
+	    !is_10bit_colorformat(colorformat))
+		supported = false;
+	if (inst->capabilities[CODED_FRAMES].value ==
+	    CODED_FRAMES_INTERLACE &&
+	    !is_ubwc_colorformat(colorformat))
+		supported = false;
+
+	return supported;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 array[32] = {0};
+	u32 i = 0;
+
+	if (f->index >= ARRAY_SIZE(array)) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	if (f->type == INPUT_MPLANE) {
+		u32 codecs = core->capabilities[DEC_CODECS].value;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (codecs & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				array[idx] = codecs & BIT(i);
+				idx++;
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_codec_from_driver(inst, array[f->index],
+							__func__);
+		if (!f->pixelformat)
+			return -EINVAL;
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+		strscpy(f->description, "codec", sizeof(f->description));
+	} else if (f->type == OUTPUT_MPLANE) {
+		u32 formats = inst->capabilities[PIX_FMTS].step_or_mask;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (formats & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				if (msm_vdec_check_colorformat_supported(inst, formats & BIT(i))) {
+					array[idx] = formats & BIT(i);
+					idx++;
+				}
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_colorformat_from_driver(inst, array[f->index],
+							      __func__);
+		if (!f->pixelformat)
+			return -EINVAL;
+		strscpy(f->description, "colorformat", sizeof(f->description));
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+
+	i_vpr_h(inst, "%s: index %d, %s: %s, flags %#x\n",
+		__func__, f->index, f->description,
+		v4l2_pixelfmt_name(inst, f->pixelformat), f->flags);
+	return rc;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct v4l2_format *f;
+	enum msm_vidc_colorformat_type colorformat;
+
+	core = inst->core;
+
+	INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler);
+	if (core->capabilities[DECODE_BATCH].value) {
+		inst->decode_batch.enable = true;
+		inst->decode_batch.size = MAX_DEC_BATCH_SIZE;
+	}
+	if (core->capabilities[DCVS].value)
+		inst->power.dcvs_mode = true;
+
+	f = &inst->fmts[INPUT_PORT];
+	f->type = INPUT_MPLANE;
+	f->fmt.pix_mp.width = DEFAULT_WIDTH;
+	f->fmt.pix_mp.height = DEFAULT_HEIGHT;
+	f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+	f->fmt.pix_mp.plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	inst->buffers.input.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_INPUT);
+	inst->buffers.input.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_INPUT);
+	inst->buffers.input.actual_count =
+			inst->buffers.input.min_count +
+			inst->buffers.input.extra_count;
+	inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->crop.left = 0;
+	inst->crop.top = 0;
+	inst->crop.width = f->fmt.pix_mp.width;
+	inst->crop.height = f->fmt.pix_mp.height;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	f->type = OUTPUT_MPLANE;
+	f->fmt.pix_mp.pixelformat =
+		v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_NV12C, __func__);
+	colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+	f->fmt.pix_mp.width = video_y_stride_pix(colorformat, DEFAULT_WIDTH);
+	f->fmt.pix_mp.height = video_y_scanlines(colorformat, DEFAULT_HEIGHT);
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline =
+		video_y_stride_bytes(colorformat, DEFAULT_WIDTH);
+	f->fmt.pix_mp.plane_fmt[0].sizeimage =
+		call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.output.min_count =
+		call_session_op(core, min_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.extra_count =
+		call_session_op(core, extra_count, inst, MSM_VIDC_BUF_OUTPUT);
+	inst->buffers.output.actual_count =
+			inst->buffers.output.min_count +
+			inst->buffers.output.extra_count;
+	inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+	inst->fw_min_count = 0;
+
+	inst->input_dpb_list_enabled = false;
+	inst->output_dpb_list_enabled = false;
+
+	rc = msm_vdec_codec_change(inst, inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat);
+
+	return rc;
+}
+
+int msm_vdec_inst_deinit(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	/* cancel pending batch work */
+	cancel_batch_work(inst);
+	rc = msm_vidc_ctrl_handler_deinit(inst);
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 09/33] iris: vidc: add control files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (7 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 08/33] iris: vidc: add video decoder files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 10/33] iris: vidc: add helper functions Vikash Garodia
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements supported v4l2 encoder and decoder controls.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_control.h |  26 +
 .../platform/qcom/iris/vidc/src/msm_vidc_control.c | 824 +++++++++++++++++++++
 2 files changed, 850 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
new file mode 100644
index 0000000..08ba77d
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_CONTROL_H_
+#define _MSM_VIDC_CONTROL_H_
+
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+int msm_vidc_ctrl_handler_init(struct msm_vidc_inst *inst, bool init);
+int msm_vidc_ctrl_handler_deinit(struct msm_vidc_inst *inst);
+int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl);
+int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
+int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl);
+int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst);
+int msm_vidc_adjust_v4l2_properties(struct msm_vidc_inst *inst);
+int msm_vidc_set_v4l2_properties(struct msm_vidc_inst *inst);
+bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id);
+bool is_valid_cap(struct msm_vidc_inst *inst,
+		  enum msm_vidc_inst_capability_type cap_id);
+enum msm_vidc_inst_capability_type msm_vidc_get_cap_id(struct msm_vidc_inst *inst,
+						       u32 id);
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
new file mode 100644
index 0000000..73b0db6
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
@@ -0,0 +1,824 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_venc.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_platform.h"
+
+static inline bool has_children(struct msm_vidc_inst_cap *cap)
+{
+	return !!cap->children[0];
+}
+
+static inline bool is_leaf(struct msm_vidc_inst_cap *cap)
+{
+	return !has_children(cap);
+}
+
+bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id)
+{
+	return cap_id > INST_CAP_NONE && cap_id < INST_CAP_MAX;
+}
+
+bool is_valid_cap(struct msm_vidc_inst *inst,
+		  enum msm_vidc_inst_capability_type cap_id)
+{
+	if (cap_id <= INST_CAP_NONE || cap_id >= INST_CAP_MAX)
+		return false;
+
+	return !!inst->capabilities[cap_id].cap_id;
+}
+
+static inline bool is_all_childrens_visited(struct msm_vidc_inst_cap *cap,
+					    bool lookup[INST_CAP_MAX])
+{
+	bool found = true;
+	int i;
+
+	for (i = 0; i < MAX_CAP_CHILDREN; i++) {
+		if (cap->children[i] == INST_CAP_NONE)
+			continue;
+
+		if (!lookup[cap->children[i]]) {
+			found = false;
+			break;
+		}
+	}
+	return found;
+}
+
+static int add_node_list(struct list_head *list, enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL;
+
+	entry = vzalloc(sizeof(*entry));
+	if (!entry) {
+		d_vpr_e("%s: allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&entry->list);
+	entry->cap_id = cap_id;
+	list_add(&entry->list, list);
+
+	return 0;
+}
+
+static int add_node(struct list_head *list, struct msm_vidc_inst_cap *lcap,
+		    bool lookup[INST_CAP_MAX])
+{
+	int rc = 0;
+
+	if (lookup[lcap->cap_id])
+		return 0;
+
+	rc = add_node_list(list, lcap->cap_id);
+	if (rc)
+		return rc;
+
+	lookup[lcap->cap_id] = true;
+	return 0;
+}
+
+static int msm_vidc_add_capid_to_fw_list(struct msm_vidc_inst *inst,
+					 enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL;
+	int rc = 0;
+
+	/* skip adding if cap_id already present in firmware list */
+	list_for_each_entry(entry, &inst->firmware_list, list) {
+		if (entry->cap_id == cap_id) {
+			i_vpr_l(inst,
+				"%s: cap[%d] %s already present in fw list\n",
+				__func__, cap_id, cap_name(cap_id));
+			return 0;
+		}
+	}
+
+	rc = add_node_list(&inst->firmware_list, cap_id);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int msm_vidc_add_children(struct msm_vidc_inst *inst,
+				 enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst_cap *cap;
+	int i, rc = 0;
+
+	cap = &inst->capabilities[cap_id];
+
+	for (i = 0; i < MAX_CAP_CHILDREN; i++) {
+		if (!cap->children[i])
+			break;
+
+		if (!is_valid_cap_id(cap->children[i]))
+			continue;
+
+		rc = add_node_list(&inst->children_list, cap->children[i]);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_adjust_cap(struct msm_vidc_inst *inst,
+			       enum msm_vidc_inst_capability_type cap_id,
+			       struct v4l2_ctrl *ctrl, const char *func)
+{
+	struct msm_vidc_inst_cap *cap;
+	int rc = 0;
+
+	/* validate cap_id */
+	if (!is_valid_cap_id(cap_id))
+		return 0;
+
+	/* validate cap */
+	cap = &inst->capabilities[cap_id];
+	if (!is_valid_cap(inst, cap->cap_id))
+		return 0;
+
+	/* check if adjust supported */
+	if (!cap->adjust) {
+		if (ctrl)
+			msm_vidc_update_cap_value(inst, cap_id, ctrl->val, func);
+		return 0;
+	}
+
+	/* call adjust */
+	rc = cap->adjust(inst, ctrl);
+	if (rc) {
+		i_vpr_e(inst, "%s: adjust cap failed for %s\n", func, cap_name(cap_id));
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_set_cap(struct msm_vidc_inst *inst,
+			    enum msm_vidc_inst_capability_type cap_id,
+			    const char *func)
+{
+	struct msm_vidc_inst_cap *cap;
+	int rc = 0;
+
+	/* validate cap_id */
+	if (!is_valid_cap_id(cap_id))
+		return 0;
+
+	/* validate cap */
+	cap = &inst->capabilities[cap_id];
+	if (!is_valid_cap(inst, cap->cap_id))
+		return 0;
+
+	/* check if set supported */
+	if (!cap->set)
+		return 0;
+
+	/* call set */
+	rc = cap->set(inst, cap_id);
+	if (rc) {
+		i_vpr_e(inst, "%s: set cap failed for %s\n", func, cap_name(cap_id));
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_adjust_dynamic_property(struct msm_vidc_inst *inst,
+					    enum msm_vidc_inst_capability_type cap_id,
+					    struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL;
+	struct msm_vidc_inst_cap *cap;
+	s32 prev_value;
+	int rc = 0;
+
+	cap = &inst->capabilities[0];
+
+	/* sanitize cap_id */
+	if (!is_valid_cap_id(cap_id)) {
+		i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+		return -EINVAL;
+	}
+
+	if (!(cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+		i_vpr_h(inst,
+			"%s: dynamic setting of cap[%d] %s is not allowed\n",
+			__func__, cap_id, cap_name(cap_id));
+		return -EBUSY;
+	}
+	i_vpr_h(inst, "%s: cap[%d] %s\n", __func__, cap_id, cap_name(cap_id));
+
+	prev_value = cap[cap_id].value;
+	rc = msm_vidc_adjust_cap(inst, cap_id, ctrl, __func__);
+	if (rc)
+		return rc;
+
+	if (cap[cap_id].value == prev_value && cap_id == GOP_SIZE) {
+		/*
+		 * Ignore setting same GOP size value to firmware to avoid
+		 * unnecessary generation of IDR frame.
+		 */
+		return 0;
+	}
+
+	/* add cap_id to firmware list always */
+	rc = msm_vidc_add_capid_to_fw_list(inst, cap_id);
+	if (rc)
+		goto error;
+
+	/* add children only if cap value modified */
+	if (cap[cap_id].value == prev_value)
+		return 0;
+
+	rc = msm_vidc_add_children(inst, cap_id);
+	if (rc)
+		goto error;
+
+	list_for_each_entry_safe(entry, temp, &inst->children_list, list) {
+		if (!is_valid_cap_id(entry->cap_id)) {
+			rc = -EINVAL;
+			goto error;
+		}
+
+		if (!cap[entry->cap_id].adjust) {
+			i_vpr_e(inst, "%s: child cap must have ajdust function %s\n",
+				__func__, cap_name(entry->cap_id));
+			rc = -EINVAL;
+			goto error;
+		}
+
+		prev_value = cap[entry->cap_id].value;
+		rc = msm_vidc_adjust_cap(inst, entry->cap_id, NULL, __func__);
+		if (rc)
+			goto error;
+
+		/* add children if cap value modified */
+		if (cap[entry->cap_id].value != prev_value) {
+			/* add cap_id to firmware list always */
+			rc = msm_vidc_add_capid_to_fw_list(inst, entry->cap_id);
+			if (rc)
+				goto error;
+
+			rc = msm_vidc_add_children(inst, entry->cap_id);
+			if (rc)
+				goto error;
+		}
+
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+
+	/* expecting children_list to be empty */
+	if (!list_empty(&inst->children_list)) {
+		i_vpr_e(inst, "%s: child_list is not empty\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	return 0;
+error:
+	list_for_each_entry_safe(entry, temp, &inst->children_list, list) {
+		i_vpr_e(inst, "%s: child list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+	list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) {
+		i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+
+	return rc;
+}
+
+static int msm_vidc_set_dynamic_property(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL;
+	int rc = 0;
+
+	list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) {
+		rc = msm_vidc_set_cap(inst, entry->cap_id, __func__);
+		if (rc)
+			goto error;
+
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+
+	return 0;
+error:
+	list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) {
+		i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+
+	return rc;
+}
+
+int msm_vidc_ctrl_handler_deinit(struct msm_vidc_inst *inst)
+{
+	i_vpr_h(inst, "%s(): num ctrls %d\n", __func__, inst->num_ctrls);
+	v4l2_ctrl_handler_free(&inst->ctrl_handler);
+	memset(&inst->ctrl_handler, 0, sizeof(struct v4l2_ctrl_handler));
+
+	return 0;
+}
+
+int msm_vidc_ctrl_handler_init(struct msm_vidc_inst *inst, bool init)
+{
+	int rc = 0;
+	struct msm_vidc_inst_cap *cap;
+	struct msm_vidc_core *core;
+	int idx = 0;
+	struct v4l2_ctrl_config ctrl_cfg = {0};
+	int num_ctrls = 0, ctrl_idx = 0;
+	u64 codecs_count, step_or_mask;
+
+	core = inst->core;
+	cap = &inst->capabilities[0];
+
+	if (!core->v4l2_ctrl_ops) {
+		i_vpr_e(inst, "%s: no control ops\n", __func__);
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < INST_CAP_MAX; idx++) {
+		if (cap[idx].v4l2_id)
+			num_ctrls++;
+	}
+	if (!num_ctrls) {
+		i_vpr_e(inst, "%s: no ctrls available in cap database\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (init) {
+		codecs_count = is_encode_session(inst) ?
+			core->enc_codecs_count :
+			core->dec_codecs_count;
+		rc = v4l2_ctrl_handler_init(&inst->ctrl_handler,
+					    INST_CAP_MAX * codecs_count);
+		if (rc) {
+			i_vpr_e(inst, "control handler init failed, %d\n",
+				inst->ctrl_handler.error);
+			goto error;
+		}
+	}
+
+	for (idx = 0; idx < INST_CAP_MAX; idx++) {
+		struct v4l2_ctrl *ctrl;
+
+		if (!cap[idx].v4l2_id)
+			continue;
+
+		if (ctrl_idx >= num_ctrls) {
+			i_vpr_e(inst,
+				"%s: invalid ctrl %#x, max allowed %d\n",
+				__func__, cap[idx].v4l2_id,
+				num_ctrls);
+			rc = -EINVAL;
+			goto error;
+		}
+		i_vpr_l(inst,
+			"%s: cap[%d] %24s, value %d min %d max %d step_or_mask %#x flags %#x v4l2_id %#x hfi_id %#x\n",
+			__func__, idx, cap_name(idx),
+			cap[idx].value,
+			cap[idx].min,
+			cap[idx].max,
+			cap[idx].step_or_mask,
+			cap[idx].flags,
+			cap[idx].v4l2_id,
+			cap[idx].hfi_id);
+
+		memset(&ctrl_cfg, 0, sizeof(struct v4l2_ctrl_config));
+
+		/*
+		 * few controls might have been already initialized in instance initialization,
+		 * so modify the range values for them instead of initializing them again
+		 */
+		if (!init) {
+			struct msm_vidc_ctrl_data ctrl_priv_data;
+
+			ctrl = v4l2_ctrl_find(&inst->ctrl_handler, cap[idx].v4l2_id);
+			if (ctrl) {
+				step_or_mask = (cap[idx].flags & CAP_FLAG_MENU) ?
+					~(cap[idx].step_or_mask) :
+					cap[idx].step_or_mask;
+				memset(&ctrl_priv_data, 0, sizeof(struct msm_vidc_ctrl_data));
+				ctrl_priv_data.skip_s_ctrl = true;
+				ctrl->priv = &ctrl_priv_data;
+				v4l2_ctrl_modify_range(ctrl,
+						       cap[idx].min,
+						       cap[idx].max,
+						       step_or_mask,
+						       cap[idx].value);
+				/* reset private data to null to ensure s_ctrl not skipped */
+				ctrl->priv = NULL;
+				continue;
+			}
+		}
+
+		if (cap[idx].flags & CAP_FLAG_MENU) {
+			ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+						      core->v4l2_ctrl_ops,
+						      cap[idx].v4l2_id,
+						      cap[idx].max,
+						      ~(cap[idx].step_or_mask),
+						      cap[idx].value);
+		} else {
+			ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
+						 core->v4l2_ctrl_ops,
+						 cap[idx].v4l2_id,
+						 cap[idx].min,
+						 cap[idx].max,
+						 cap[idx].step_or_mask,
+						 cap[idx].value);
+		}
+		if (!ctrl) {
+			i_vpr_e(inst, "%s: invalid ctrl %#x cap %24s\n", __func__,
+				cap[idx].v4l2_id, cap_name(idx));
+			rc = -EINVAL;
+			goto error;
+		}
+
+		rc = inst->ctrl_handler.error;
+		if (rc) {
+			i_vpr_e(inst,
+				"error adding ctrl (%#x) to ctrl handle, %d\n",
+				cap[idx].v4l2_id,
+				inst->ctrl_handler.error);
+			goto error;
+		}
+
+		if (cap[idx].flags & CAP_FLAG_VOLATILE)
+			ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+		ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+		ctrl_idx++;
+	}
+	inst->num_ctrls = num_ctrls;
+	i_vpr_h(inst, "%s(): num ctrls %d\n", __func__, inst->num_ctrls);
+
+	return 0;
+error:
+	msm_vidc_ctrl_handler_deinit(inst);
+
+	return rc;
+}
+
+static int
+msm_vidc_update_buffer_count_if_needed(struct msm_vidc_inst *inst,
+				       enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	bool update_input_port = false, update_output_port = false;
+
+	switch (cap_id) {
+	case LAYER_TYPE:
+	case ENH_LAYER_COUNT:
+	case LAYER_ENABLE:
+		update_input_port = true;
+		break;
+	default:
+		update_input_port = false;
+		update_output_port = false;
+		break;
+	}
+
+	if (update_input_port) {
+		rc = msm_vidc_update_buffer_count(inst, INPUT_PORT);
+		if (rc)
+			return rc;
+	}
+	if (update_output_port) {
+		rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+
+	if (!ctrl) {
+		d_vpr_e("%s: invalid ctrl parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = container_of(ctrl->handler,
+			    struct msm_vidc_inst, ctrl_handler);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: could not find inst for ctrl %s id %#x\n",
+			__func__, ctrl->name, ctrl->id);
+		return -EINVAL;
+	}
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+
+	rc = msm_vidc_get_control(inst, ctrl);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed for ctrl %s id %#x\n",
+			__func__, ctrl->name, ctrl->id);
+		goto unlock;
+	} else {
+		i_vpr_h(inst, "%s: ctrl %s id %#x, value %d\n",
+			__func__, ctrl->name, ctrl->id, ctrl->val);
+	}
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+	return rc;
+}
+
+static int
+msm_vidc_update_static_property(struct msm_vidc_inst *inst,
+				enum msm_vidc_inst_capability_type cap_id,
+				struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	/* update value to db */
+	msm_vidc_update_cap_value(inst, cap_id, ctrl->val, __func__);
+
+	if (cap_id == ROTATION) {
+		struct v4l2_format *output_fmt;
+
+		output_fmt = &inst->fmts[OUTPUT_PORT];
+		rc = msm_venc_s_fmt_output(inst, output_fmt);
+		if (rc)
+			return rc;
+	}
+
+	if (cap_id == BITSTREAM_SIZE_OVERWRITE) {
+		rc = msm_vidc_update_bitstream_buffer_size(inst);
+		if (rc)
+			return rc;
+	}
+
+	if (cap_id == ENH_LAYER_COUNT && inst->codec == MSM_VIDC_HEVC) {
+		u32 enable;
+
+		/* enable LAYER_ENABLE cap if HEVC_HIER enh layers > 0 */
+		if (ctrl->val > 0)
+			enable = 1;
+		else
+			enable = 0;
+
+		msm_vidc_update_cap_value(inst, LAYER_ENABLE, enable, __func__);
+	}
+
+	rc = msm_vidc_update_buffer_count_if_needed(inst, cap_id);
+
+	return rc;
+}
+
+int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	enum msm_vidc_inst_capability_type cap_id;
+	struct msm_vidc_inst_cap *cap;
+	int rc = 0;
+	u32 port;
+
+	cap = &inst->capabilities[0];
+
+	i_vpr_h(inst, FMT_STRING_SET_CTRL,
+		__func__, state_name(inst->state), ctrl->name, ctrl->id, ctrl->val);
+
+	cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+	if (!is_valid_cap_id(cap_id)) {
+		i_vpr_e(inst, "%s: invalid cap_id for ctrl %s\n", __func__, ctrl->name);
+		return -EINVAL;
+	}
+
+	/* mark client set flag */
+	cap[cap_id].flags |= CAP_FLAG_CLIENT_SET;
+
+	port = is_encode_session(inst) ? OUTPUT_PORT : INPUT_PORT;
+	if (!inst->bufq[port].vb2q->streaming) {
+		/* static case */
+		rc = msm_vidc_update_static_property(inst, cap_id, ctrl);
+		if (rc)
+			return rc;
+	} else {
+		/* dynamic case */
+		rc = msm_vidc_adjust_dynamic_property(inst, cap_id, ctrl);
+		if (rc)
+			return rc;
+
+		rc = msm_vidc_set_dynamic_property(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst;
+	struct msm_vidc_ctrl_data *priv_ctrl_data;
+	int rc = 0;
+
+	if (!ctrl) {
+		d_vpr_e("%s: invalid ctrl parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * v4l2_ctrl_modify_range may internally call s_ctrl
+	 * which will again try to acquire lock leading to deadlock,
+	 * Add check to avoid such scenario.
+	 */
+	priv_ctrl_data = ctrl->priv ? ctrl->priv : NULL;
+	if (priv_ctrl_data && priv_ctrl_data->skip_s_ctrl) {
+		d_vpr_l("%s: skip s_ctrl (%s)\n", __func__, ctrl->name);
+		return 0;
+	}
+
+	inst = container_of(ctrl->handler, struct msm_vidc_inst, ctrl_handler);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = inst->event_handle(inst, MSM_VIDC_S_CTRL, ctrl);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+	return rc;
+}
+
+int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst)
+{
+	struct list_head leaf_list, opt_list;
+	struct msm_vidc_inst_cap *cap, *lcap, *temp_cap;
+	struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL;
+	bool leaf_visited[INST_CAP_MAX];
+	bool opt_visited[INST_CAP_MAX];
+	int tmp_count_total, tmp_count, num_nodes = 0;
+	int i, rc = 0;
+
+	cap = &inst->capabilities[0];
+
+	if (!list_empty(&inst->caps_list)) {
+		i_vpr_h(inst, "%s: dependency list already prepared\n", __func__);
+		return 0;
+	}
+
+	/* init local list and lookup table entries */
+	INIT_LIST_HEAD(&leaf_list);
+	INIT_LIST_HEAD(&opt_list);
+	memset(&leaf_visited, 0, sizeof(leaf_visited));
+	memset(&opt_visited, 0, sizeof(opt_visited));
+
+	/* populate leaf nodes first */
+	for (i = 1; i < INST_CAP_MAX; i++) {
+		lcap = &cap[i];
+		if (!is_valid_cap(inst, lcap->cap_id))
+			continue;
+
+		/* sanitize cap value */
+		if (i != lcap->cap_id) {
+			i_vpr_e(inst, "%s: cap id mismatch. expected %s, actual %s\n",
+				__func__, cap_name(i), cap_name(lcap->cap_id));
+			rc = -EINVAL;
+			goto error;
+		}
+
+		/* add all leaf nodes */
+		if (is_leaf(lcap)) {
+			rc = add_node(&leaf_list, lcap, leaf_visited);
+			if (rc)
+				goto error;
+		} else {
+			rc = add_node(&opt_list, lcap, opt_visited);
+			if (rc)
+				goto error;
+		}
+	}
+
+	/* find total optional list entries */
+	list_for_each_entry(entry, &opt_list, list)
+		num_nodes++;
+
+	/* used for loop detection */
+	tmp_count_total = num_nodes;
+	tmp_count = num_nodes;
+
+	/* sort final outstanding nodes */
+	list_for_each_entry_safe(entry, temp, &opt_list, list) {
+		/* initially remove entry from opt list */
+		list_del_init(&entry->list);
+		opt_visited[entry->cap_id] = false;
+		tmp_count--;
+		temp_cap = &cap[entry->cap_id];
+
+		/**
+		 * if all child are visited then add this entry to
+		 * leaf list else add it to the end of optional list.
+		 */
+		if (is_all_childrens_visited(temp_cap, leaf_visited)) {
+			list_add(&entry->list, &leaf_list);
+			leaf_visited[entry->cap_id] = true;
+			tmp_count_total--;
+		} else {
+			list_add_tail(&entry->list, &opt_list);
+			opt_visited[entry->cap_id] = true;
+		}
+
+		/* detect loop */
+		if (!tmp_count) {
+			if (num_nodes == tmp_count_total) {
+				i_vpr_e(inst, "%s: loop detected in subgraph %d\n",
+					__func__, num_nodes);
+				rc = -EINVAL;
+				goto error;
+			}
+			num_nodes = tmp_count_total;
+			tmp_count = tmp_count_total;
+		}
+	}
+
+	/* expecting opt_list to be empty */
+	if (!list_empty(&opt_list)) {
+		i_vpr_e(inst, "%s: opt_list is not empty\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* move elements to &inst->caps_list from local */
+	list_replace_init(&leaf_list, &inst->caps_list);
+
+	return 0;
+error:
+	list_for_each_entry_safe(entry, temp, &opt_list, list) {
+		i_vpr_e(inst, "%s: opt_list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+	list_for_each_entry_safe(entry, temp, &leaf_list, list) {
+		i_vpr_e(inst, "%s: leaf_list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del_init(&entry->list);
+		vfree(entry);
+	}
+	return rc;
+}
+
+int msm_vidc_adjust_v4l2_properties(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL;
+	int rc = 0;
+
+	/* adjust all possible caps from caps_list */
+	list_for_each_entry_safe(entry, temp, &inst->caps_list, list) {
+		i_vpr_l(inst, "%s: cap: id %3u, name %s\n", __func__,
+			entry->cap_id, cap_name(entry->cap_id));
+
+		rc = msm_vidc_adjust_cap(inst, entry->cap_id, NULL, __func__);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_set_v4l2_properties(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL;
+	int rc = 0;
+
+	/* set all caps from caps_list */
+	list_for_each_entry_safe(entry, temp, &inst->caps_list, list) {
+		rc = msm_vidc_set_cap(inst, entry->cap_id, __func__);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 10/33] iris: vidc: add helper functions
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (8 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 09/33] iris: vidc: add control files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:41   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 11/33] iris: vidc: add helpers for memory management Vikash Garodia
                   ` (25 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements common helper functions for v4l2 to vidc and
vice versa conversion for different enums.
Add helpers for state checks, buffer management, locks etc.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_driver.h  |  352 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_driver.c  | 4276 ++++++++++++++++++++
 2 files changed, 4628 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
new file mode 100644
index 0000000..459e540
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_DRIVER_H_
+#define _MSM_VIDC_DRIVER_H_
+
+#include <linux/iommu.h>
+#include <linux/workqueue.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+extern struct msm_vidc_core *g_core;
+
+#define MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS 1000
+
+enum msm_vidc_debugfs_event;
+
+static inline bool is_decode_session(struct msm_vidc_inst *inst)
+{
+	return inst->domain == MSM_VIDC_DECODER;
+}
+
+static inline bool is_encode_session(struct msm_vidc_inst *inst)
+{
+	return inst->domain == MSM_VIDC_ENCODER;
+}
+
+static inline bool is_input_buffer(enum msm_vidc_buffer_type buffer_type)
+{
+	return buffer_type == MSM_VIDC_BUF_INPUT;
+}
+
+static inline bool is_output_buffer(enum msm_vidc_buffer_type buffer_type)
+{
+	return buffer_type == MSM_VIDC_BUF_OUTPUT;
+}
+
+static inline bool is_scaling_enabled(struct msm_vidc_inst *inst)
+{
+	return inst->crop.left != inst->compose.left ||
+		inst->crop.top != inst->compose.top ||
+		inst->crop.width != inst->compose.width ||
+		inst->crop.height != inst->compose.height;
+}
+
+static inline bool is_rotation_90_or_270(struct msm_vidc_inst *inst)
+{
+	return inst->capabilities[ROTATION].value == 90 ||
+		inst->capabilities[ROTATION].value == 270;
+}
+
+static inline bool is_internal_buffer(enum msm_vidc_buffer_type buffer_type)
+{
+	return buffer_type == MSM_VIDC_BUF_BIN ||
+		buffer_type == MSM_VIDC_BUF_ARP ||
+		buffer_type == MSM_VIDC_BUF_COMV ||
+		buffer_type == MSM_VIDC_BUF_NON_COMV ||
+		buffer_type == MSM_VIDC_BUF_LINE ||
+		buffer_type == MSM_VIDC_BUF_DPB ||
+		buffer_type == MSM_VIDC_BUF_PERSIST ||
+		buffer_type == MSM_VIDC_BUF_VPSS;
+}
+
+static inline bool is_linear_yuv_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_NV12 ||
+		colorformat == MSM_VIDC_FMT_NV21 ||
+		colorformat == MSM_VIDC_FMT_P010;
+}
+
+static inline bool is_linear_rgba_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_RGBA8888;
+}
+
+static inline bool is_linear_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return is_linear_yuv_colorformat(colorformat) || is_linear_rgba_colorformat(colorformat);
+}
+
+static inline bool is_ubwc_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_NV12C ||
+		colorformat == MSM_VIDC_FMT_TP10C ||
+		colorformat == MSM_VIDC_FMT_RGBA8888C;
+}
+
+static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_P010 ||
+		colorformat == MSM_VIDC_FMT_TP10C;
+}
+
+static inline bool is_8bit_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_NV12 ||
+		colorformat == MSM_VIDC_FMT_NV12C ||
+		colorformat == MSM_VIDC_FMT_NV21 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888C;
+}
+
+static inline bool is_rgba_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_RGBA8888 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888C;
+}
+
+static inline bool is_split_mode_enabled(struct msm_vidc_inst *inst)
+{
+	if (!is_decode_session(inst))
+		return false;
+
+	if (is_linear_colorformat(inst->capabilities[PIX_FMTS].value))
+		return true;
+
+	return false;
+}
+
+static inline bool is_low_power_session(struct msm_vidc_inst *inst)
+{
+	return (inst->capabilities[QUALITY_MODE].value ==
+		MSM_VIDC_POWER_SAVE_MODE);
+}
+
+static inline bool is_hierb_type_requested(struct msm_vidc_inst *inst)
+{
+	return (inst->codec == MSM_VIDC_H264 &&
+		inst->capabilities[LAYER_TYPE].value ==
+				V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) ||
+			(inst->codec == MSM_VIDC_HEVC &&
+			inst->capabilities[LAYER_TYPE].value ==
+				V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B);
+}
+
+static inline bool is_active_session(u64 prev, u64 curr)
+{
+	u64 ts_delta;
+
+	if (!prev || !curr)
+		return true;
+
+	ts_delta = (prev < curr) ? curr - prev : prev - curr;
+
+	return ((ts_delta / NSEC_PER_MSEC) <=
+			MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS);
+}
+
+static inline bool is_session_error(struct msm_vidc_inst *inst)
+{
+	return inst->state == MSM_VIDC_ERROR;
+}
+
+static inline bool is_secure_region(enum msm_vidc_buffer_region region)
+{
+	return !(region == MSM_VIDC_NON_SECURE ||
+			region == MSM_VIDC_NON_SECURE_PIXEL);
+}
+
+const char *cap_name(enum msm_vidc_inst_capability_type cap_id);
+const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixelfmt);
+const char *v4l2_type_name(u32 port);
+void print_vidc_buffer(u32 tag, const char *tag_str, const char *str, struct msm_vidc_inst *inst,
+		       struct msm_vidc_buffer *vbuf);
+void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst,
+		      struct vb2_buffer *vb2);
+enum msm_vidc_codec_type v4l2_codec_to_driver(struct msm_vidc_inst *inst,
+					      u32 v4l2_codec, const char *func);
+u32 v4l2_codec_from_driver(struct msm_vidc_inst *inst, enum msm_vidc_codec_type codec,
+			   const char *func);
+enum msm_vidc_colorformat_type v4l2_colorformat_to_driver(struct msm_vidc_inst *inst,
+							  u32 colorformat, const char *func);
+u32 v4l2_colorformat_from_driver(struct msm_vidc_inst *inst,
+				 enum msm_vidc_colorformat_type colorformat, const char *func);
+u32 v4l2_color_primaries_to_driver(struct msm_vidc_inst *inst,
+				   u32 v4l2_primaries, const char *func);
+u32 v4l2_color_primaries_from_driver(struct msm_vidc_inst *inst,
+				     u32 vidc_color_primaries, const char *func);
+u32 v4l2_transfer_char_to_driver(struct msm_vidc_inst *inst,
+				 u32 v4l2_transfer_char, const char *func);
+u32 v4l2_transfer_char_from_driver(struct msm_vidc_inst *inst,
+				   u32 vidc_transfer_char, const char *func);
+u32 v4l2_matrix_coeff_to_driver(struct msm_vidc_inst *inst,
+				u32 v4l2_matrix_coeff, const char *func);
+u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst,
+				  u32 vidc_matrix_coeff, const char *func);
+int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type,
+			     const char *func);
+const char *allow_name(enum msm_vidc_allow allow);
+int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
+				    enum msm_vidc_buffer_type buffer_type, u32 index);
+int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst,
+				  enum msm_vidc_buffer_type buffer_type);
+int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
+				     enum msm_vidc_buffer_type buffer_type);
+int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst,
+				    enum msm_vidc_buffer_type buffer_type);
+int msm_vidc_alloc_and_queue_session_int_bufs(struct msm_vidc_inst *inst,
+					      enum msm_vidc_buffer_type buffer_type);
+int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
+				      enum msm_vidc_buffer_type buffer_type);
+int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
+			     struct msm_vidc_buffer *buf);
+int msm_vidc_remove_dangling_session(struct msm_vidc_inst *inst);
+int msm_vidc_remove_session(struct msm_vidc_inst *inst);
+int msm_vidc_add_session(struct msm_vidc_inst *inst);
+int msm_vidc_session_open(struct msm_vidc_inst *inst);
+int msm_vidc_session_set_codec(struct msm_vidc_inst *inst);
+int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst);
+int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
+			       enum msm_vidc_port_type port);
+int msm_vidc_session_close(struct msm_vidc_inst *inst);
+int msm_vidc_kill_session(struct msm_vidc_inst *inst);
+int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst);
+int msm_vidc_change_core_state(struct msm_vidc_core *core,
+			       enum msm_vidc_core_state request_state, const char *func);
+int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
+				   enum msm_vidc_core_sub_state clear_sub_states,
+				   enum msm_vidc_core_sub_state set_sub_states, const char *func);
+int msm_vidc_core_init(struct msm_vidc_core *core);
+int msm_vidc_core_init_wait(struct msm_vidc_core *core);
+int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force);
+int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force);
+int msm_vidc_inst_timeout(struct msm_vidc_inst *inst);
+int msm_vidc_print_buffer_info(struct msm_vidc_inst *inst);
+int msm_vidc_print_inst_info(struct msm_vidc_inst *inst);
+void msm_vidc_print_core_info(struct msm_vidc_core *core);
+int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
+				struct device *dev, unsigned long iova, int flags, void *data);
+void msm_vidc_fw_unload_handler(struct work_struct *work);
+int msm_vidc_suspend(struct msm_vidc_core *core);
+void msm_vidc_batch_handler(struct work_struct *work);
+int msm_vidc_v4l2_fh_init(struct msm_vidc_inst *inst);
+int msm_vidc_v4l2_fh_deinit(struct msm_vidc_inst *inst);
+int msm_vidc_vb2_queue_init(struct msm_vidc_inst *inst);
+int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst);
+int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl);
+struct msm_vidc_buffers *msm_vidc_get_buffers(struct msm_vidc_inst *inst,
+					      enum msm_vidc_buffer_type buffer_type,
+					      const char *func);
+struct msm_vidc_mem_list *msm_vidc_get_mem_info(struct msm_vidc_inst *inst,
+						enum msm_vidc_buffer_type buffer_type,
+						const char *func);
+struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst,
+						struct vb2_buffer *vb2);
+int msm_vidc_allocate_buffers(struct msm_vidc_inst *inst,
+			      enum msm_vidc_buffer_type buf_type, u32 num_buffers);
+int msm_vidc_free_buffers(struct msm_vidc_inst *inst,
+			  enum msm_vidc_buffer_type buf_type);
+void msm_vidc_update_stats(struct msm_vidc_inst *inst,
+			   struct msm_vidc_buffer *buf,
+			   enum msm_vidc_debugfs_event etype);
+void msm_vidc_stats_handler(struct work_struct *work);
+int schedule_stats_work(struct msm_vidc_inst *inst);
+int cancel_stats_work_sync(struct msm_vidc_inst *inst);
+void msm_vidc_print_stats(struct msm_vidc_inst *inst);
+void msm_vidc_print_memory_stats(struct msm_vidc_inst *inst);
+enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type, const char *func);
+int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf);
+int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
+int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst,
+				    enum msm_vidc_buffer_type buf_type);
+int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst,
+				     struct msm_vidc_buffer *buffer);
+void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst);
+int msm_vidc_flush_buffers(struct msm_vidc_inst *inst,
+			   enum msm_vidc_buffer_type type);
+int msm_vidc_flush_read_only_buffers(struct msm_vidc_inst *inst,
+				     enum msm_vidc_buffer_type type);
+struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core,
+				   struct msm_vidc_inst *instance);
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+			       u32 session_id);
+void put_inst(struct msm_vidc_inst *inst);
+enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst);
+bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst);
+bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst);
+enum msm_vidc_allow msm_vidc_allow_pm_suspend(struct msm_vidc_core *core);
+int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, u32 type);
+int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, u32 type);
+int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst);
+int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst);
+int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst);
+int msm_vidc_process_drain(struct msm_vidc_inst *inst);
+int msm_vidc_process_resume(struct msm_vidc_inst *inst);
+int msm_vidc_process_streamon_input(struct msm_vidc_inst *inst);
+int msm_vidc_process_streamon_output(struct msm_vidc_inst *inst);
+int msm_vidc_process_stop_done(struct msm_vidc_inst *inst,
+			       enum signal_session_response signal_type);
+int msm_vidc_process_drain_done(struct msm_vidc_inst *inst);
+int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst);
+int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst);
+int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst);
+u32 msm_vidc_get_max_bitrate(struct msm_vidc_inst *inst);
+int msm_vidc_get_fps(struct msm_vidc_inst *inst);
+int msm_vidc_num_buffers(struct msm_vidc_inst *inst,
+			 enum msm_vidc_buffer_type type,
+			 enum msm_vidc_buffer_attributes attr);
+void core_lock(struct msm_vidc_core *core, const char *function);
+void core_unlock(struct msm_vidc_core *core, const char *function);
+void inst_lock(struct msm_vidc_inst *inst, const char *function);
+void inst_unlock(struct msm_vidc_inst *inst, const char *function);
+void client_lock(struct msm_vidc_inst *inst, const char *function);
+void client_unlock(struct msm_vidc_inst *inst, const char *function);
+int msm_vidc_update_bitstream_buffer_size(struct msm_vidc_inst *inst);
+int msm_vidc_update_buffer_count(struct msm_vidc_inst *inst, u32 port);
+void msm_vidc_schedule_core_deinit(struct msm_vidc_core *core);
+int msm_vidc_init_core_caps(struct msm_vidc_core *core);
+int msm_vidc_init_instance_caps(struct msm_vidc_core *core);
+int msm_vidc_update_debug_str(struct msm_vidc_inst *inst);
+void msm_vidc_allow_dcvs(struct msm_vidc_inst *inst);
+bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
+bool msm_vidc_ignore_session_load(struct msm_vidc_inst *inst);
+int msm_vidc_check_core_mbps(struct msm_vidc_inst *inst);
+int msm_vidc_check_core_mbpf(struct msm_vidc_inst *inst);
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
+int msm_vidc_update_timestamp_rate(struct msm_vidc_inst *inst, u64 timestamp);
+int msm_vidc_get_timestamp_rate(struct msm_vidc_inst *inst);
+int msm_vidc_flush_ts(struct msm_vidc_inst *inst);
+const char *buf_name(enum msm_vidc_buffer_type type);
+bool res_is_greater_than(u32 width, u32 height,
+			 u32 ref_width, u32 ref_height);
+bool res_is_greater_than_or_equal_to(u32 width, u32 height,
+				     u32 ref_width, u32 ref_height);
+bool res_is_less_than(u32 width, u32 height,
+		      u32 ref_width, u32 ref_height);
+bool res_is_less_than_or_equal_to(u32 width, u32 height,
+				  u32 ref_width, u32 ref_height);
+bool is_hevc_10bit_decode_session(struct msm_vidc_inst *inst);
+int signal_session_msg_receipt(struct msm_vidc_inst *inst,
+			       enum signal_session_response cmd);
+int msm_vidc_get_properties(struct msm_vidc_inst *inst);
+int msm_vidc_update_input_rate(struct msm_vidc_inst *inst, u64 time_us);
+int msm_vidc_get_input_rate(struct msm_vidc_inst *inst);
+int msm_vidc_get_frame_rate(struct msm_vidc_inst *inst);
+int msm_vidc_get_operating_rate(struct msm_vidc_inst *inst);
+int msm_vidc_alloc_and_queue_input_internal_buffers(struct msm_vidc_inst *inst);
+int vb2_buffer_to_driver(struct vb2_buffer *vb2, struct msm_vidc_buffer *buf);
+struct msm_vidc_buffer *msm_vidc_fetch_buffer(struct msm_vidc_inst *inst,
+					      struct vb2_buffer *vb2);
+struct context_bank_info *msm_vidc_get_context_bank_for_region(struct msm_vidc_core *core,
+							       enum msm_vidc_buffer_region region);
+struct context_bank_info *msm_vidc_get_context_bank_for_device(struct msm_vidc_core *core,
+							       struct device *dev);
+
+#endif // _MSM_VIDC_DRIVER_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
new file mode 100644
index 0000000..029fc71
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
@@ -0,0 +1,4276 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/iommu.h>
+#include <linux/workqueue.h>
+
+#include "hfi_packet.h"
+#include "msm_media_info.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "msm_vidc_state.h"
+#include "venus_hfi.h"
+#include "venus_hfi_response.h"
+
+#define is_odd(val) ((val) % 2 == 1)
+#define in_range(val, min, max) (((min) <= (val)) && ((val) <= (max)))
+#define COUNT_BITS(a, out) {       \
+	while ((a) >= 1) {          \
+		(out) += (a) & (1); \
+		(a) >>= (1);        \
+	}                           \
+}
+
+/* do not modify the cap names as it is used in test scripts */
+static const char * const cap_name_arr[] = {
+	[INST_CAP_NONE] =               "INST_CAP_NONE",
+	[MIN_FRAME_QP] =                "MIN_FRAME_QP",
+	[MAX_FRAME_QP] =                "MAX_FRAME_QP",
+	[I_FRAME_QP] =                  "I_FRAME_QP",
+	[P_FRAME_QP] =                  "P_FRAME_QP",
+	[B_FRAME_QP] =                  "B_FRAME_QP",
+	[TIME_DELTA_BASED_RC] =         "TIME_DELTA_BASED_RC",
+	[CONSTANT_QUALITY] =            "CONSTANT_QUALITY",
+	[VBV_DELAY] =                   "VBV_DELAY",
+	[PEAK_BITRATE] =                "PEAK_BITRATE",
+	[ENTROPY_MODE] =                "ENTROPY_MODE",
+	[TRANSFORM_8X8] =               "TRANSFORM_8X8",
+	[STAGE] =                       "STAGE",
+	[LTR_COUNT] =                   "LTR_COUNT",
+	[IR_PERIOD] =                   "IR_PERIOD",
+	[BITRATE_BOOST] =               "BITRATE_BOOST",
+	[OUTPUT_ORDER] =                "OUTPUT_ORDER",
+	[INPUT_BUF_HOST_MAX_COUNT] =    "INPUT_BUF_HOST_MAX_COUNT",
+	[OUTPUT_BUF_HOST_MAX_COUNT] =   "OUTPUT_BUF_HOST_MAX_COUNT",
+	[VUI_TIMING_INFO] =             "VUI_TIMING_INFO",
+	[SLICE_DECODE] =                "SLICE_DECODE",
+	[PROFILE] =                     "PROFILE",
+	[ENH_LAYER_COUNT] =             "ENH_LAYER_COUNT",
+	[BIT_RATE] =                    "BIT_RATE",
+	[GOP_SIZE] =                    "GOP_SIZE",
+	[B_FRAME] =                     "B_FRAME",
+	[ALL_INTRA] =                   "ALL_INTRA",
+	[MIN_QUALITY] =                 "MIN_QUALITY",
+	[SLICE_MODE] =                  "SLICE_MODE",
+	[FRAME_WIDTH] =                 "FRAME_WIDTH",
+	[LOSSLESS_FRAME_WIDTH] =        "LOSSLESS_FRAME_WIDTH",
+	[FRAME_HEIGHT] =                "FRAME_HEIGHT",
+	[LOSSLESS_FRAME_HEIGHT] =       "LOSSLESS_FRAME_HEIGHT",
+	[PIX_FMTS] =                    "PIX_FMTS",
+	[MIN_BUFFERS_INPUT] =           "MIN_BUFFERS_INPUT",
+	[MIN_BUFFERS_OUTPUT] =          "MIN_BUFFERS_OUTPUT",
+	[MBPF] =                        "MBPF",
+	[BATCH_MBPF] =                  "BATCH_MBPF",
+	[BATCH_FPS] =                   "BATCH_FPS",
+	[LOSSLESS_MBPF] =               "LOSSLESS_MBPF",
+	[FRAME_RATE] =                  "FRAME_RATE",
+	[OPERATING_RATE] =              "OPERATING_RATE",
+	[INPUT_RATE] =                  "INPUT_RATE",
+	[TIMESTAMP_RATE] =              "TIMESTAMP_RATE",
+	[SCALE_FACTOR] =                "SCALE_FACTOR",
+	[MB_CYCLES_VSP] =               "MB_CYCLES_VSP",
+	[MB_CYCLES_VPP] =               "MB_CYCLES_VPP",
+	[MB_CYCLES_LP] =                "MB_CYCLES_LP",
+	[MB_CYCLES_FW] =                "MB_CYCLES_FW",
+	[MB_CYCLES_FW_VPP] =            "MB_CYCLES_FW_VPP",
+	[ENC_RING_BUFFER_COUNT] =       "ENC_RING_BUFFER_COUNT",
+	[HFLIP] =                       "HFLIP",
+	[VFLIP] =                       "VFLIP",
+	[ROTATION] =                    "ROTATION",
+	[HEADER_MODE] =                 "HEADER_MODE",
+	[PREPEND_SPSPPS_TO_IDR] =       "PREPEND_SPSPPS_TO_IDR",
+	[WITHOUT_STARTCODE] =           "WITHOUT_STARTCODE",
+	[NAL_LENGTH_FIELD] =            "NAL_LENGTH_FIELD",
+	[REQUEST_I_FRAME] =             "REQUEST_I_FRAME",
+	[BITRATE_MODE] =                "BITRATE_MODE",
+	[LOSSLESS] =                    "LOSSLESS",
+	[FRAME_SKIP_MODE] =             "FRAME_SKIP_MODE",
+	[FRAME_RC_ENABLE] =             "FRAME_RC_ENABLE",
+	[GOP_CLOSURE] =                 "GOP_CLOSURE",
+	[USE_LTR] =                     "USE_LTR",
+	[MARK_LTR] =                    "MARK_LTR",
+	[BASELAYER_PRIORITY] =          "BASELAYER_PRIORITY",
+	[IR_TYPE] =                     "IR_TYPE",
+	[AU_DELIMITER] =                "AU_DELIMITER",
+	[GRID_ENABLE] =                 "GRID_ENABLE",
+	[GRID_SIZE] =                   "GRID_SIZE",
+	[I_FRAME_MIN_QP] =              "I_FRAME_MIN_QP",
+	[P_FRAME_MIN_QP] =              "P_FRAME_MIN_QP",
+	[B_FRAME_MIN_QP] =              "B_FRAME_MIN_QP",
+	[I_FRAME_MAX_QP] =              "I_FRAME_MAX_QP",
+	[P_FRAME_MAX_QP] =              "P_FRAME_MAX_QP",
+	[B_FRAME_MAX_QP] =              "B_FRAME_MAX_QP",
+	[LAYER_TYPE] =                  "LAYER_TYPE",
+	[LAYER_ENABLE] =                "LAYER_ENABLE",
+	[L0_BR] =                       "L0_BR",
+	[L1_BR] =                       "L1_BR",
+	[L2_BR] =                       "L2_BR",
+	[L3_BR] =                       "L3_BR",
+	[L4_BR] =                       "L4_BR",
+	[L5_BR] =                       "L5_BR",
+	[LEVEL] =                       "LEVEL",
+	[HEVC_TIER] =                   "HEVC_TIER",
+	[DISPLAY_DELAY_ENABLE] =        "DISPLAY_DELAY_ENABLE",
+	[DISPLAY_DELAY] =               "DISPLAY_DELAY",
+	[CONCEAL_COLOR_8BIT] =          "CONCEAL_COLOR_8BIT",
+	[CONCEAL_COLOR_10BIT] =         "CONCEAL_COLOR_10BIT",
+	[LF_MODE] =                     "LF_MODE",
+	[LF_ALPHA] =                    "LF_ALPHA",
+	[LF_BETA] =                     "LF_BETA",
+	[SLICE_MAX_BYTES] =             "SLICE_MAX_BYTES",
+	[SLICE_MAX_MB] =                "SLICE_MAX_MB",
+	[MB_RC] =                       "MB_RC",
+	[CHROMA_QP_INDEX_OFFSET] =      "CHROMA_QP_INDEX_OFFSET",
+	[PIPE] =                        "PIPE",
+	[POC] =                         "POC",
+	[CODED_FRAMES] =                "CODED_FRAMES",
+	[BIT_DEPTH] =                   "BIT_DEPTH",
+	[BITSTREAM_SIZE_OVERWRITE] =    "BITSTREAM_SIZE_OVERWRITE",
+	[DEFAULT_HEADER] =              "DEFAULT_HEADER",
+	[RAP_FRAME] =                   "RAP_FRAME",
+	[SEQ_CHANGE_AT_SYNC_FRAME] =    "SEQ_CHANGE_AT_SYNC_FRAME",
+	[QUALITY_MODE] =                "QUALITY_MODE",
+	[CABAC_MAX_BITRATE] =           "CABAC_MAX_BITRATE",
+	[CAVLC_MAX_BITRATE] =           "CAVLC_MAX_BITRATE",
+	[ALLINTRA_MAX_BITRATE] =        "ALLINTRA_MAX_BITRATE",
+	[NUM_COMV] =                    "NUM_COMV",
+	[SIGNAL_COLOR_INFO] =           "SIGNAL_COLOR_INFO",
+	[INST_CAP_MAX] =                "INST_CAP_MAX",
+};
+
+const char *cap_name(enum msm_vidc_inst_capability_type cap_id)
+{
+	const char *name = "UNKNOWN CAP";
+
+	if (cap_id >= ARRAY_SIZE(cap_name_arr))
+		goto exit;
+
+	name = cap_name_arr[cap_id];
+
+exit:
+	return name;
+}
+
+static const char * const buf_type_name_arr[] = {
+	[MSM_VIDC_BUF_NONE] =            "NONE",
+	[MSM_VIDC_BUF_INPUT] =           "INPUT",
+	[MSM_VIDC_BUF_OUTPUT] =          "OUTPUT",
+	[MSM_VIDC_BUF_READ_ONLY] =       "READ_ONLY",
+	[MSM_VIDC_BUF_INTERFACE_QUEUE] = "INTERFACE_QUEUE",
+	[MSM_VIDC_BUF_BIN] =             "BIN",
+	[MSM_VIDC_BUF_ARP] =             "ARP",
+	[MSM_VIDC_BUF_COMV] =            "COMV",
+	[MSM_VIDC_BUF_NON_COMV] =        "NON_COMV",
+	[MSM_VIDC_BUF_LINE] =            "LINE",
+	[MSM_VIDC_BUF_DPB] =             "DPB",
+	[MSM_VIDC_BUF_PERSIST] =         "PERSIST",
+	[MSM_VIDC_BUF_VPSS] =            "VPSS"
+};
+
+const char *buf_name(enum msm_vidc_buffer_type type)
+{
+	const char *name = "UNKNOWN BUF";
+
+	if (type >= ARRAY_SIZE(buf_type_name_arr))
+		goto exit;
+
+	name = buf_type_name_arr[type];
+
+exit:
+	return name;
+}
+
+static const char * const inst_allow_name_arr[] = {
+	[MSM_VIDC_DISALLOW] = "MSM_VIDC_DISALLOW",
+	[MSM_VIDC_ALLOW] = "MSM_VIDC_ALLOW",
+	[MSM_VIDC_DEFER] = "MSM_VIDC_DEFER",
+	[MSM_VIDC_DISCARD] = "MSM_VIDC_DISCARD",
+	[MSM_VIDC_IGNORE] = "MSM_VIDC_IGNORE",
+};
+
+const char *allow_name(enum msm_vidc_allow allow)
+{
+	const char *name = "UNKNOWN";
+
+	if (allow >= ARRAY_SIZE(inst_allow_name_arr))
+		goto exit;
+
+	name = inst_allow_name_arr[allow];
+
+exit:
+	return name;
+}
+
+const char *v4l2_type_name(u32 port)
+{
+	switch (port) {
+	case INPUT_MPLANE:      return "INPUT";
+	case OUTPUT_MPLANE:     return "OUTPUT";
+	}
+
+	return "UNKNOWN";
+}
+
+const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixfmt)
+{
+	struct msm_vidc_core *core;
+	const struct codec_info *codec_info;
+	const struct color_format_info *color_format_info;
+	u32 i, size;
+
+	core = inst->core;
+	codec_info = core->platform->data.format_data->codec_info;
+	size = core->platform->data.format_data->codec_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (codec_info[i].v4l2_codec == pixfmt)
+			return codec_info[i].pixfmt_name;
+	}
+
+	color_format_info = core->platform->data.format_data->color_format_info;
+	size = core->platform->data.format_data->color_format_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (color_format_info[i].v4l2_color_format == pixfmt)
+			return color_format_info[i].pixfmt_name;
+	}
+
+	return "UNKNOWN";
+}
+
+void print_vidc_buffer(u32 tag, const char *tag_str, const char *str, struct msm_vidc_inst *inst,
+		       struct msm_vidc_buffer *vbuf)
+{
+	struct dma_buf *dbuf;
+	struct inode *f_inode;
+	unsigned long inode_num = 0;
+	long ref_count = -1;
+
+	if (!vbuf || !tag_str || !str)
+		return;
+
+	dbuf = (struct dma_buf *)vbuf->dmabuf;
+	if (dbuf && dbuf->file) {
+		f_inode = file_inode(dbuf->file);
+		if (f_inode) {
+			inode_num = f_inode->i_ino;
+			ref_count = file_count(dbuf->file);
+		}
+	}
+
+	dprintk_inst(tag, tag_str, inst,
+		     "%s: %s: idx %2d fd %3d off %d daddr %#llx inode %8lu ref %2ld size %8d filled %8d flags %#x ts %8lld attr %#x dbuf_get %d attach %d map %d counts(etb ebd ftb fbd) %4llu %4llu %4llu %4llu\n",
+		     str, buf_name(vbuf->type),
+		     vbuf->index, vbuf->fd, vbuf->data_offset,
+		     vbuf->device_addr, inode_num, ref_count, vbuf->buffer_size,
+		     vbuf->data_size, vbuf->flags, vbuf->timestamp, vbuf->attr,
+		     vbuf->dbuf_get, vbuf->attach ? 1 : 0, vbuf->sg_table ? 1 : 0,
+		     inst->debug_count.etb, inst->debug_count.ebd,
+		     inst->debug_count.ftb, inst->debug_count.fbd);
+}
+
+void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst,
+		      struct vb2_buffer *vb2)
+{
+	i_vpr_e(inst,
+		"%s: %s: idx %2d fd %d off %d size %d filled %d\n",
+		str, vb2->type == INPUT_MPLANE ? "INPUT" : "OUTPUT",
+		vb2->index, vb2->planes[0].m.fd,
+		vb2->planes[0].data_offset, vb2->planes[0].length,
+		vb2->planes[0].bytesused);
+}
+
+int msm_vidc_suspend(struct msm_vidc_core *core)
+{
+	return venus_hfi_suspend(core);
+}
+
+enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type, const char *func)
+{
+	enum msm_vidc_buffer_type buffer_type = 0;
+
+	switch (type) {
+	case INPUT_MPLANE:
+		buffer_type = MSM_VIDC_BUF_INPUT;
+		break;
+	case OUTPUT_MPLANE:
+		buffer_type = MSM_VIDC_BUF_OUTPUT;
+		break;
+	default:
+		d_vpr_e("%s: invalid v4l2 buffer type %#x\n", func, type);
+		break;
+	}
+	return buffer_type;
+}
+
+u32 v4l2_type_from_driver(enum msm_vidc_buffer_type buffer_type,
+			  const char *func)
+{
+	u32 type = 0;
+
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_INPUT:
+		type = INPUT_MPLANE;
+		break;
+	case MSM_VIDC_BUF_OUTPUT:
+		type = OUTPUT_MPLANE;
+		break;
+	default:
+		d_vpr_e("%s: invalid driver buffer type %d\n",
+			func, buffer_type);
+		break;
+	}
+	return type;
+}
+
+enum msm_vidc_codec_type v4l2_codec_to_driver(struct msm_vidc_inst *inst,
+					      u32 v4l2_codec, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct codec_info *codec_info;
+	u32 i, size;
+	enum msm_vidc_codec_type codec = 0;
+
+	core = inst->core;
+	codec_info = core->platform->data.format_data->codec_info;
+	size = core->platform->data.format_data->codec_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (codec_info[i].v4l2_codec == v4l2_codec)
+			return codec_info[i].vidc_codec;
+	}
+
+	d_vpr_h("%s: invalid v4l2 codec %#x\n", func, v4l2_codec);
+	return codec;
+}
+
+u32 v4l2_codec_from_driver(struct msm_vidc_inst *inst,
+			   enum msm_vidc_codec_type codec, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct codec_info *codec_info;
+	u32 i, size;
+	u32 v4l2_codec = 0;
+
+	core = inst->core;
+	codec_info = core->platform->data.format_data->codec_info;
+	size = core->platform->data.format_data->codec_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (codec_info[i].vidc_codec == codec)
+			return codec_info[i].v4l2_codec;
+	}
+
+	d_vpr_e("%s: invalid driver codec %#x\n", func, codec);
+	return v4l2_codec;
+}
+
+enum msm_vidc_colorformat_type v4l2_colorformat_to_driver(struct msm_vidc_inst *inst,
+							  u32 v4l2_colorformat,
+							  const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct color_format_info *color_format_info;
+	u32 i, size;
+	enum msm_vidc_colorformat_type colorformat = 0;
+
+	core = inst->core;
+	color_format_info = core->platform->data.format_data->color_format_info;
+	size = core->platform->data.format_data->color_format_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (color_format_info[i].v4l2_color_format == v4l2_colorformat)
+			return color_format_info[i].vidc_color_format;
+	}
+
+	d_vpr_e("%s: invalid v4l2 color format %#x\n", func, v4l2_colorformat);
+	return colorformat;
+}
+
+u32 v4l2_colorformat_from_driver(struct msm_vidc_inst *inst,
+				 enum msm_vidc_colorformat_type colorformat,
+				 const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct color_format_info *color_format_info;
+	u32 i, size;
+	u32 v4l2_colorformat = 0;
+
+	core = inst->core;
+	color_format_info = core->platform->data.format_data->color_format_info;
+	size = core->platform->data.format_data->color_format_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (color_format_info[i].vidc_color_format == colorformat)
+			return color_format_info[i].v4l2_color_format;
+	}
+
+	d_vpr_e("%s: invalid driver color format %#x\n", func, colorformat);
+	return v4l2_colorformat;
+}
+
+u32 v4l2_color_primaries_to_driver(struct msm_vidc_inst *inst,
+				   u32 v4l2_primaries, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct color_primaries_info *color_prim_info;
+	u32 i, size;
+	u32 vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED;
+
+	core = inst->core;
+	color_prim_info = core->platform->data.format_data->color_prim_info;
+	size = core->platform->data.format_data->color_prim_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (color_prim_info[i].v4l2_color_primaries == v4l2_primaries)
+			return color_prim_info[i].vidc_color_primaries;
+	}
+
+	i_vpr_e(inst, "%s: invalid v4l2 color primaries %d\n",
+		func, v4l2_primaries);
+
+	return vidc_color_primaries;
+}
+
+u32 v4l2_color_primaries_from_driver(struct msm_vidc_inst *inst,
+				     u32 vidc_color_primaries, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct color_primaries_info *color_prim_info;
+	u32 i, size;
+	u32 v4l2_primaries = V4L2_COLORSPACE_DEFAULT;
+
+	core = inst->core;
+	color_prim_info = core->platform->data.format_data->color_prim_info;
+	size = core->platform->data.format_data->color_prim_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (color_prim_info[i].vidc_color_primaries == vidc_color_primaries)
+			return color_prim_info[i].v4l2_color_primaries;
+	}
+
+	i_vpr_e(inst, "%s: invalid hfi color primaries %d\n",
+		func, vidc_color_primaries);
+
+	return v4l2_primaries;
+}
+
+u32 v4l2_transfer_char_to_driver(struct msm_vidc_inst *inst,
+				 u32 v4l2_transfer_char, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct transfer_char_info *transfer_char_info;
+	u32 i, size;
+	u32 vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED;
+
+	core = inst->core;
+	transfer_char_info = core->platform->data.format_data->transfer_char_info;
+	size = core->platform->data.format_data->transfer_char_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (transfer_char_info[i].v4l2_transfer_char == v4l2_transfer_char)
+			return transfer_char_info[i].vidc_transfer_char;
+	}
+
+	i_vpr_e(inst, "%s: invalid v4l2 transfer char %d\n",
+		func, v4l2_transfer_char);
+
+	return vidc_transfer_char;
+}
+
+u32 v4l2_transfer_char_from_driver(struct msm_vidc_inst *inst,
+				   u32 vidc_transfer_char, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct transfer_char_info *transfer_char_info;
+	u32 i, size;
+	u32  v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT;
+
+	core = inst->core;
+	transfer_char_info = core->platform->data.format_data->transfer_char_info;
+	size = core->platform->data.format_data->transfer_char_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (transfer_char_info[i].vidc_transfer_char == vidc_transfer_char)
+			return transfer_char_info[i].v4l2_transfer_char;
+	}
+
+	i_vpr_e(inst, "%s: invalid hfi transfer char %d\n",
+		func, vidc_transfer_char);
+
+	return v4l2_transfer_char;
+}
+
+u32 v4l2_matrix_coeff_to_driver(struct msm_vidc_inst *inst,
+				u32 v4l2_matrix_coeff, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct matrix_coeff_info *matrix_coeff_info;
+	u32 i, size;
+	u32 vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED;
+
+	core = inst->core;
+	matrix_coeff_info = core->platform->data.format_data->matrix_coeff_info;
+	size = core->platform->data.format_data->matrix_coeff_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (matrix_coeff_info[i].v4l2_matrix_coeff == v4l2_matrix_coeff)
+			return matrix_coeff_info[i].vidc_matrix_coeff;
+	}
+
+	i_vpr_e(inst, "%s: invalid v4l2 matrix coeff %d\n",
+		func, v4l2_matrix_coeff);
+
+	return vidc_matrix_coeff;
+}
+
+u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst,
+				  u32 vidc_matrix_coeff, const char *func)
+{
+	struct msm_vidc_core *core;
+	const struct matrix_coeff_info *matrix_coeff_info;
+	u32 i, size;
+	u32 v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT;
+
+	core = inst->core;
+	matrix_coeff_info = core->platform->data.format_data->matrix_coeff_info;
+	size = core->platform->data.format_data->matrix_coeff_info_size;
+
+	for (i = 0; i < size; i++) {
+		if (matrix_coeff_info[i].vidc_matrix_coeff == vidc_matrix_coeff)
+			return matrix_coeff_info[i].v4l2_matrix_coeff;
+	}
+
+	i_vpr_e(inst, "%s: invalid hfi matrix coeff %d\n",
+		func, vidc_matrix_coeff);
+
+	return v4l2_matrix_coeff;
+}
+
+int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type,
+			     const char *func)
+{
+	int port;
+
+	if (type == INPUT_MPLANE) {
+		port = INPUT_PORT;
+	} else if (type == OUTPUT_MPLANE) {
+		port = OUTPUT_PORT;
+	} else {
+		i_vpr_e(inst, "%s: port not found for v4l2 type %d\n",
+			func, type);
+		port = -EINVAL;
+	}
+
+	return port;
+}
+
+struct msm_vidc_buffers *msm_vidc_get_buffers(struct msm_vidc_inst *inst,
+					      enum msm_vidc_buffer_type buffer_type,
+					      const char *func)
+{
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_INPUT:
+		return &inst->buffers.input;
+	case MSM_VIDC_BUF_OUTPUT:
+		return &inst->buffers.output;
+	case MSM_VIDC_BUF_READ_ONLY:
+		return &inst->buffers.read_only;
+	case MSM_VIDC_BUF_BIN:
+		return &inst->buffers.bin;
+	case MSM_VIDC_BUF_ARP:
+		return &inst->buffers.arp;
+	case MSM_VIDC_BUF_COMV:
+		return &inst->buffers.comv;
+	case MSM_VIDC_BUF_NON_COMV:
+		return &inst->buffers.non_comv;
+	case MSM_VIDC_BUF_LINE:
+		return &inst->buffers.line;
+	case MSM_VIDC_BUF_DPB:
+		return &inst->buffers.dpb;
+	case MSM_VIDC_BUF_PERSIST:
+		return &inst->buffers.persist;
+	case MSM_VIDC_BUF_VPSS:
+		return &inst->buffers.vpss;
+	case MSM_VIDC_BUF_INTERFACE_QUEUE:
+		return NULL;
+	default:
+		i_vpr_e(inst, "%s: invalid driver buffer type %d\n",
+			func, buffer_type);
+		return NULL;
+	}
+}
+
+struct msm_vidc_mem_list *msm_vidc_get_mem_info(struct msm_vidc_inst *inst,
+						enum msm_vidc_buffer_type buffer_type,
+						const char *func)
+{
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_BIN:
+		return &inst->mem_info.bin;
+	case MSM_VIDC_BUF_ARP:
+		return &inst->mem_info.arp;
+	case MSM_VIDC_BUF_COMV:
+		return &inst->mem_info.comv;
+	case MSM_VIDC_BUF_NON_COMV:
+		return &inst->mem_info.non_comv;
+	case MSM_VIDC_BUF_LINE:
+		return &inst->mem_info.line;
+	case MSM_VIDC_BUF_DPB:
+		return &inst->mem_info.dpb;
+	case MSM_VIDC_BUF_PERSIST:
+		return &inst->mem_info.persist;
+	case MSM_VIDC_BUF_VPSS:
+		return &inst->mem_info.vpss;
+	default:
+		i_vpr_e(inst, "%s: invalid driver buffer type %d\n",
+			func, buffer_type);
+		return NULL;
+	}
+}
+
+bool res_is_greater_than(u32 width, u32 height,
+			 u32 ref_width, u32 ref_height)
+{
+	u32 num_mbs = NUM_MBS_PER_FRAME(height, width);
+	u32 max_side = max(ref_width, ref_height);
+
+	if (num_mbs > NUM_MBS_PER_FRAME(ref_height, ref_width) ||
+	    width > max_side ||
+	    height > max_side)
+		return true;
+	else
+		return false;
+}
+
+bool res_is_greater_than_or_equal_to(u32 width, u32 height,
+				     u32 ref_width, u32 ref_height)
+{
+	u32 num_mbs = NUM_MBS_PER_FRAME(height, width);
+	u32 max_side = max(ref_width, ref_height);
+
+	if (num_mbs >= NUM_MBS_PER_FRAME(ref_height, ref_width) ||
+	    width >= max_side ||
+	    height >= max_side)
+		return true;
+	else
+		return false;
+}
+
+bool res_is_less_than(u32 width, u32 height,
+		      u32 ref_width, u32 ref_height)
+{
+	u32 num_mbs = NUM_MBS_PER_FRAME(height, width);
+	u32 max_side = max(ref_width, ref_height);
+
+	if (num_mbs < NUM_MBS_PER_FRAME(ref_height, ref_width) &&
+	    width < max_side &&
+	    height < max_side)
+		return true;
+	else
+		return false;
+}
+
+bool res_is_less_than_or_equal_to(u32 width, u32 height,
+				  u32 ref_width, u32 ref_height)
+{
+	u32 num_mbs = NUM_MBS_PER_FRAME(height, width);
+	u32 max_side = max(ref_width, ref_height);
+
+	if (num_mbs <= NUM_MBS_PER_FRAME(ref_height, ref_width) &&
+	    width <= max_side &&
+	    height <= max_side)
+		return true;
+	else
+		return false;
+}
+
+int signal_session_msg_receipt(struct msm_vidc_inst *inst,
+			       enum signal_session_response cmd)
+{
+	if (cmd < MAX_SIGNAL)
+		complete(&inst->completions[cmd]);
+	return 0;
+}
+
+enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst)
+{
+	enum msm_vidc_allow allow = MSM_VIDC_ALLOW;
+	/*
+	 * if drc sequence is not completed by client, fw is not
+	 * expected to raise another ipsc
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC)) {
+		i_vpr_e(inst, "%s: not allowed in sub state %s\n",
+			__func__, inst->sub_state_name);
+		return MSM_VIDC_DISALLOW;
+	}
+
+	return allow;
+}
+
+bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst)
+{
+	/*
+	 * drain last flag is expected only when DRAIN, INPUT_PAUSE
+	 * is set and DRAIN_LAST_BUFFER is not set
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRAIN) &&
+	    is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) &&
+	    !is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER))
+		return true;
+
+	i_vpr_e(inst, "%s: not allowed in sub state %s\n",
+		__func__, inst->sub_state_name);
+	return false;
+}
+
+bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst)
+{
+	/*
+	 * drc last flag is expected only when DRC, INPUT_PAUSE
+	 * is set and DRC_LAST_BUFFER is not set
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC) &&
+	    is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) &&
+	    !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER))
+		return true;
+
+	i_vpr_e(inst, "%s: not allowed in sub state %s\n",
+		__func__, inst->sub_state_name);
+
+	return false;
+}
+
+enum msm_vidc_allow msm_vidc_allow_pm_suspend(struct msm_vidc_core *core)
+{
+	/* core must be in valid state to do pm_suspend */
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return MSM_VIDC_DISALLOW;
+	}
+
+	/* check if power is enabled */
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_h("%s: Power already disabled\n", __func__);
+		return MSM_VIDC_IGNORE;
+	}
+
+	return MSM_VIDC_ALLOW;
+}
+
+bool is_hevc_10bit_decode_session(struct msm_vidc_inst *inst)
+{
+	bool is10bit = false;
+	enum msm_vidc_colorformat_type colorformat;
+
+	/* in case of decoder session return false */
+	if (!is_decode_session(inst))
+		return false;
+
+	colorformat =
+		v4l2_colorformat_to_driver(inst,
+					   inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
+					   __func__);
+
+	if (colorformat == MSM_VIDC_FMT_TP10C || colorformat == MSM_VIDC_FMT_P010)
+		is10bit = true;
+
+	return is_decode_session(inst) &&
+				inst->codec == MSM_VIDC_HEVC &&
+				is10bit;
+}
+
+int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst,
+				   enum msm_vidc_port_type port)
+{
+	enum msm_vidc_state new_state = MSM_VIDC_ERROR;
+
+	if (port == INPUT_PORT) {
+		if (is_state(inst, MSM_VIDC_OPEN))
+			new_state = MSM_VIDC_INPUT_STREAMING;
+		else if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING))
+			new_state = MSM_VIDC_STREAMING;
+	} else if (port == OUTPUT_PORT) {
+		if (is_state(inst, MSM_VIDC_OPEN))
+			new_state = MSM_VIDC_OUTPUT_STREAMING;
+		else if (is_state(inst, MSM_VIDC_INPUT_STREAMING))
+			new_state = MSM_VIDC_STREAMING;
+	}
+
+	return msm_vidc_change_state(inst, new_state, __func__);
+}
+
+int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst,
+				    enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	enum msm_vidc_state new_state = MSM_VIDC_ERROR;
+
+	if (port == INPUT_PORT) {
+		if (is_state(inst, MSM_VIDC_INPUT_STREAMING))
+			new_state = MSM_VIDC_OPEN;
+		else if (is_state(inst, MSM_VIDC_STREAMING))
+			new_state = MSM_VIDC_OUTPUT_STREAMING;
+	} else if (port == OUTPUT_PORT) {
+		if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING))
+			new_state = MSM_VIDC_OPEN;
+		else if (is_state(inst, MSM_VIDC_STREAMING))
+			new_state = MSM_VIDC_INPUT_STREAMING;
+	}
+	rc = msm_vidc_change_state(inst, new_state, __func__);
+	if (rc)
+		goto exit;
+
+exit:
+	return rc;
+}
+
+int msm_vidc_process_drain(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = venus_hfi_session_drain(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+	rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_DRAIN, __func__);
+	if (rc)
+		return rc;
+
+	msm_vidc_scale_power(inst, true);
+
+	return rc;
+}
+
+int msm_vidc_process_resume(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE;
+	bool drain_pending = false;
+
+	msm_vidc_scale_power(inst, true);
+
+	/* first check DRC pending else check drain pending */
+	if (is_sub_state(inst, MSM_VIDC_DRC) &&
+	    is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) {
+		clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER;
+		/*
+		 * if drain sequence is not completed then do not resume here.
+		 * client will eventually complete drain sequence in which ports
+		 * will be resumed.
+		 */
+		drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) &&
+			is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER);
+		if (!drain_pending) {
+			if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+				rc = venus_hfi_session_resume(inst, INPUT_PORT,
+							      HFI_CMD_SETTINGS_CHANGE);
+				if (rc)
+					return rc;
+				clear_sub_state |= MSM_VIDC_INPUT_PAUSE;
+			}
+			if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) {
+				rc = venus_hfi_session_resume(inst, OUTPUT_PORT,
+							      HFI_CMD_SETTINGS_CHANGE);
+				if (rc)
+					return rc;
+				clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE;
+			}
+		}
+	} else if (is_sub_state(inst, MSM_VIDC_DRAIN) &&
+			   is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) {
+		clear_sub_state = MSM_VIDC_DRAIN | MSM_VIDC_DRAIN_LAST_BUFFER;
+		if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+			rc = venus_hfi_session_resume(inst, INPUT_PORT, HFI_CMD_DRAIN);
+			if (rc)
+				return rc;
+			clear_sub_state |= MSM_VIDC_INPUT_PAUSE;
+		}
+		if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) {
+			rc = venus_hfi_session_resume(inst, OUTPUT_PORT, HFI_CMD_DRAIN);
+			if (rc)
+				return rc;
+			clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE;
+		}
+	}
+
+	rc = msm_vidc_change_sub_state(inst, clear_sub_state, 0, __func__);
+
+	return rc;
+}
+
+int msm_vidc_process_streamon_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE;
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+
+	msm_vidc_scale_power(inst, true);
+
+	rc = venus_hfi_start(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	/* clear input pause substate immediately */
+	if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+		rc = msm_vidc_change_sub_state(inst, MSM_VIDC_INPUT_PAUSE, 0, __func__);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * if DRC sequence is not completed by the client then PAUSE
+	 * firmware input port to avoid firmware raising IPSC again.
+	 * When client completes DRC or DRAIN sequences, firmware
+	 * input port will be resumed.
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC) ||
+	    is_sub_state(inst, MSM_VIDC_DRAIN)) {
+		if (!is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+			rc = venus_hfi_session_pause(inst, INPUT_PORT);
+			if (rc)
+				return rc;
+			set_sub_state = MSM_VIDC_INPUT_PAUSE;
+		}
+	}
+
+	rc = msm_vidc_state_change_streamon(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_change_sub_state(inst, clear_sub_state, set_sub_state, __func__);
+
+	return rc;
+}
+
+int msm_vidc_process_streamon_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE;
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+	bool drain_pending = false;
+
+	msm_vidc_scale_power(inst, true);
+
+	/*
+	 * client completed drc sequence, reset DRC and
+	 * MSM_VIDC_DRC_LAST_BUFFER substates
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC) &&
+	    is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) {
+		clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER;
+	}
+	/*
+	 * Client is completing port reconfiguration, hence reallocate
+	 * input internal buffers before input port is resumed.
+	 * Drc sub-state cannot be checked because DRC sub-state will
+	 * not be set during initial port reconfiguration.
+	 */
+	if (is_decode_session(inst) &&
+	    is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+		rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst);
+		if (rc)
+			return rc;
+		rc = msm_vidc_set_stage(inst, STAGE);
+		if (rc)
+			return rc;
+		rc = msm_vidc_set_pipe(inst, PIPE);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * fw input port is paused due to ipsc. now that client
+	 * completed drc sequence, resume fw input port provided
+	 * drain is not pending and input port is streaming.
+	 */
+	drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) &&
+		is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER);
+	if (!drain_pending && is_state(inst, MSM_VIDC_INPUT_STREAMING)) {
+		if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+			rc = venus_hfi_session_resume(inst, INPUT_PORT,
+						      HFI_CMD_SETTINGS_CHANGE);
+			if (rc)
+				return rc;
+			clear_sub_state |= MSM_VIDC_INPUT_PAUSE;
+		}
+	}
+
+	rc = venus_hfi_start(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	/* clear output pause substate immediately */
+	if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) {
+		rc = msm_vidc_change_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE, 0, __func__);
+		if (rc)
+			return rc;
+	}
+
+	rc = msm_vidc_state_change_streamon(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_change_sub_state(inst, clear_sub_state, set_sub_state, __func__);
+
+	return rc;
+}
+
+int msm_vidc_process_stop_done(struct msm_vidc_inst *inst,
+			       enum signal_session_response signal_type)
+{
+	int rc = 0;
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+
+	if (signal_type == SIGNAL_CMD_STOP_INPUT) {
+		set_sub_state = MSM_VIDC_INPUT_PAUSE;
+		/*
+		 * FW is expected to return DRC LAST flag before input
+		 * stop done if DRC sequence is pending
+		 */
+		if (is_sub_state(inst, MSM_VIDC_DRC) &&
+		    !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) {
+			i_vpr_e(inst, "%s: drc last flag pkt not received\n", __func__);
+			msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+		/*
+		 * for a decode session, FW is expected to return
+		 * DRAIN LAST flag before input stop done if
+		 * DRAIN sequence is pending
+		 */
+		if (is_decode_session(inst) &&
+		    is_sub_state(inst, MSM_VIDC_DRAIN) &&
+			!is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) {
+			i_vpr_e(inst, "%s: drain last flag pkt not received\n", __func__);
+			msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+	} else if (signal_type == SIGNAL_CMD_STOP_OUTPUT) {
+		set_sub_state = MSM_VIDC_OUTPUT_PAUSE;
+	}
+
+	rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__);
+	if (rc)
+		return rc;
+
+	signal_session_msg_receipt(inst, signal_type);
+	return rc;
+}
+
+int msm_vidc_process_drain_done(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (is_sub_state(inst, MSM_VIDC_DRAIN)) {
+		rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_INPUT_PAUSE, __func__);
+		if (rc)
+			return rc;
+	} else {
+		i_vpr_e(inst, "%s: unexpected drain done\n", __func__);
+	}
+
+	return rc;
+}
+
+int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_state_change_drain_last_flag(inst);
+}
+
+int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_state_change_psc_last_flag(inst);
+}
+
+int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst)
+{
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+
+	/*
+	 * if output port is not streaming, then do not set DRC substate
+	 * because DRC_LAST_FLAG is not going to be received. Update
+	 * INPUT_PAUSE substate only
+	 */
+	if (is_state(inst, MSM_VIDC_INPUT_STREAMING) ||
+	    is_state(inst, MSM_VIDC_OPEN))
+		set_sub_state = MSM_VIDC_INPUT_PAUSE;
+	else
+		set_sub_state = MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE;
+
+	return msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__);
+}
+
+int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst)
+{
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+
+	set_sub_state = MSM_VIDC_DRAIN_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE;
+	return msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__);
+}
+
+int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst)
+{
+	enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE;
+
+	set_sub_state = MSM_VIDC_DRC_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE;
+	return msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__);
+}
+
+int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	enum msm_vidc_inst_capability_type cap_id;
+
+	cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+	if (!is_valid_cap_id(cap_id)) {
+		i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n",
+			__func__, ctrl->name);
+		return -EINVAL;
+	}
+
+	switch (cap_id) {
+	case MIN_BUFFERS_OUTPUT:
+		ctrl->val = inst->buffers.output.min_count +
+			inst->buffers.output.extra_count;
+		i_vpr_h(inst, "g_min: output buffers %d\n", ctrl->val);
+		break;
+	case MIN_BUFFERS_INPUT:
+		ctrl->val = inst->buffers.input.min_count +
+			inst->buffers.input.extra_count;
+		i_vpr_h(inst, "g_min: input buffers %d\n", ctrl->val);
+		break;
+	default:
+		i_vpr_e(inst, "invalid ctrl %s id %d\n",
+			ctrl->name, ctrl->id);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int height = 0, width = 0;
+	struct v4l2_format *inp_f;
+
+	if (is_decode_session(inst)) {
+		inp_f = &inst->fmts[INPUT_PORT];
+		width = max(inp_f->fmt.pix_mp.width, inst->crop.width);
+		height = max(inp_f->fmt.pix_mp.height, inst->crop.height);
+	} else if (is_encode_session(inst)) {
+		width = inst->crop.width;
+		height = inst->crop.height;
+	}
+
+	return NUM_MBS_PER_FRAME(height, width);
+}
+
+int msm_vidc_get_fps(struct msm_vidc_inst *inst)
+{
+	int fps;
+	u32 frame_rate, operating_rate;
+
+	frame_rate = msm_vidc_get_frame_rate(inst);
+	operating_rate = msm_vidc_get_operating_rate(inst);
+
+	if (operating_rate > frame_rate)
+		fps = operating_rate ? operating_rate : 1;
+	else
+		fps = frame_rate;
+
+	return fps;
+}
+
+int msm_vidc_num_buffers(struct msm_vidc_inst *inst,
+			 enum msm_vidc_buffer_type type,
+			 enum msm_vidc_buffer_attributes attr)
+{
+	int count = 0;
+	struct msm_vidc_buffer *vbuf;
+	struct msm_vidc_buffers *buffers;
+
+	if (is_output_buffer(type)) {
+		buffers = &inst->buffers.output;
+	} else if (is_input_buffer(type)) {
+		buffers = &inst->buffers.input;
+	} else {
+		i_vpr_e(inst, "%s: invalid buffer type %#x\n",
+			__func__, type);
+		return count;
+	}
+
+	list_for_each_entry(vbuf, &buffers->list, list) {
+		if (vbuf->type != type)
+			continue;
+		if (!(vbuf->attr & attr))
+			continue;
+		count++;
+	}
+
+	return count;
+}
+
+int vb2_buffer_to_driver(struct vb2_buffer *vb2,
+			 struct msm_vidc_buffer *buf)
+{
+	int rc = 0;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (!vb2 || !buf) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	vbuf = to_vb2_v4l2_buffer(vb2);
+
+	buf->fd = vb2->planes[0].m.fd;
+	buf->data_offset = vb2->planes[0].data_offset;
+	buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset;
+	buf->buffer_size = vb2->planes[0].length;
+	buf->timestamp = vb2->timestamp;
+	buf->flags = vbuf->flags;
+	buf->attr = 0;
+
+	return rc;
+}
+
+int msm_vidc_process_readonly_buffers(struct msm_vidc_inst *inst,
+				      struct msm_vidc_buffer *buf)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (!is_decode_session(inst) || !is_output_buffer(buf->type))
+		return 0;
+
+	/*
+	 * check if read_only buffer is present in read_only list
+	 * if present: add ro flag to buf provided buffer is not
+	 * pending release
+	 */
+	list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+		if (ro_buf->device_addr != buf->device_addr)
+			continue;
+		if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY &&
+		    !(ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)) {
+			/* add READ_ONLY to the buffer going to the firmware */
+			buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
+			/*
+			 * remove READ_ONLY on the read_only list buffer so that
+			 * it will get removed from the read_only list below
+			 */
+			ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
+			break;
+		}
+	}
+
+	/* remove ro buffers if not required anymore */
+	list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+		/* if read only buffer do not remove */
+		if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)
+			continue;
+
+		print_vidc_buffer(VIDC_LOW, "low ", "ro buf removed", inst, ro_buf);
+		/* unmap the buffer if driver holds mapping */
+		if (ro_buf->sg_table && ro_buf->attach) {
+			call_mem_op(core, dma_buf_unmap_attachment, core,
+				    ro_buf->attach, ro_buf->sg_table);
+			call_mem_op(core, dma_buf_detach, core,
+				    ro_buf->dmabuf, ro_buf->attach);
+			ro_buf->sg_table = NULL;
+			ro_buf->attach = NULL;
+		}
+		if (ro_buf->dbuf_get) {
+			call_mem_op(core, dma_buf_put, inst, ro_buf->dmabuf);
+			ro_buf->dmabuf = NULL;
+			ro_buf->dbuf_get = 0;
+		}
+
+		list_del_init(&ro_buf->list);
+		msm_vidc_pool_free(inst, ro_buf);
+	}
+
+	return rc;
+}
+
+int msm_vidc_update_input_rate(struct msm_vidc_inst *inst, u64 time_us)
+{
+	struct msm_vidc_input_timer *input_timer;
+	struct msm_vidc_input_timer *prev_timer = NULL;
+	struct msm_vidc_core *core;
+	u64 counter = 0;
+	u64 input_timer_sum_us = 0;
+
+	core = inst->core;
+
+	input_timer = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUF_TIMER);
+	if (!input_timer)
+		return -ENOMEM;
+
+	input_timer->time_us = time_us;
+	INIT_LIST_HEAD(&input_timer->list);
+	list_add_tail(&input_timer->list, &inst->input_timer_list);
+	list_for_each_entry(input_timer, &inst->input_timer_list, list) {
+		if (prev_timer) {
+			input_timer_sum_us += input_timer->time_us - prev_timer->time_us;
+			counter++;
+		}
+		prev_timer = input_timer;
+	}
+
+	if (input_timer_sum_us && counter >= INPUT_TIMER_LIST_SIZE)
+		inst->capabilities[INPUT_RATE].value =
+			(s32)(DIV64_U64_ROUND_CLOSEST(counter * 1000000,
+				input_timer_sum_us) << 16);
+
+	/* delete the first entry once counter >= INPUT_TIMER_LIST_SIZE */
+	if (counter >= INPUT_TIMER_LIST_SIZE) {
+		input_timer = list_first_entry(&inst->input_timer_list,
+					       struct msm_vidc_input_timer, list);
+		list_del_init(&input_timer->list);
+		msm_vidc_pool_free(inst, input_timer);
+	}
+
+	return 0;
+}
+
+int msm_vidc_flush_input_timer(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_input_timer *input_timer, *dummy_timer;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	i_vpr_l(inst, "%s: flush input_timer list\n", __func__);
+	list_for_each_entry_safe(input_timer, dummy_timer, &inst->input_timer_list, list) {
+		list_del_init(&input_timer->list);
+		msm_vidc_pool_free(inst, input_timer);
+	}
+	return 0;
+}
+
+int msm_vidc_get_input_rate(struct msm_vidc_inst *inst)
+{
+	return inst->capabilities[INPUT_RATE].value >> 16;
+}
+
+int msm_vidc_get_timestamp_rate(struct msm_vidc_inst *inst)
+{
+	return inst->capabilities[TIMESTAMP_RATE].value >> 16;
+}
+
+int msm_vidc_get_frame_rate(struct msm_vidc_inst *inst)
+{
+	return inst->capabilities[FRAME_RATE].value >> 16;
+}
+
+int msm_vidc_get_operating_rate(struct msm_vidc_inst *inst)
+{
+	return inst->capabilities[OPERATING_RATE].value >> 16;
+}
+
+static int msm_vidc_insert_sort(struct list_head *head,
+				struct msm_vidc_sort *entry)
+{
+	struct msm_vidc_sort *first, *node;
+	struct msm_vidc_sort *prev = NULL;
+	bool is_inserted = false;
+
+	if (!head || !entry) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (list_empty(head)) {
+		list_add(&entry->list, head);
+		return 0;
+	}
+
+	first = list_first_entry(head, struct msm_vidc_sort, list);
+	if (entry->val < first->val) {
+		list_add(&entry->list, head);
+		return 0;
+	}
+
+	list_for_each_entry(node, head, list) {
+		if (prev &&
+		    entry->val >= prev->val && entry->val <= node->val) {
+			list_add(&entry->list, &prev->list);
+			is_inserted = true;
+			break;
+		}
+		prev = node;
+	}
+
+	if (!is_inserted && prev)
+		list_add(&entry->list, &prev->list);
+
+	return 0;
+}
+
+static struct msm_vidc_timestamp *msm_vidc_get_least_rank_ts(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_timestamp *ts, *final = NULL;
+	u64 least_rank = INT_MAX;
+
+	list_for_each_entry(ts, &inst->timestamps.list, sort.list) {
+		if (ts->rank < least_rank) {
+			least_rank = ts->rank;
+			final = ts;
+		}
+	}
+
+	return final;
+}
+
+int msm_vidc_flush_ts(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_timestamp *temp, *ts = NULL;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	list_for_each_entry_safe(ts, temp, &inst->timestamps.list, sort.list) {
+		i_vpr_l(inst, "%s: flushing ts: val %llu, rank %llu\n",
+			__func__, ts->sort.val, ts->rank);
+		list_del(&ts->sort.list);
+		msm_vidc_pool_free(inst, ts);
+	}
+	inst->timestamps.count = 0;
+	inst->timestamps.rank = 0;
+
+	return 0;
+}
+
+int msm_vidc_update_timestamp_rate(struct msm_vidc_inst *inst, u64 timestamp)
+{
+	struct msm_vidc_timestamp *ts, *prev = NULL;
+	struct msm_vidc_core *core;
+	int rc = 0;
+	u32 window_size = 0;
+	u32 timestamp_rate = 0;
+	u64 ts_ms = 0;
+	u32 counter = 0;
+
+	core = inst->core;
+
+	ts = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_TIMESTAMP);
+	if (!ts) {
+		i_vpr_e(inst, "%s: ts alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&ts->sort.list);
+	ts->sort.val = timestamp;
+	ts->rank = inst->timestamps.rank++;
+	rc = msm_vidc_insert_sort(&inst->timestamps.list, &ts->sort);
+	if (rc)
+		return rc;
+	inst->timestamps.count++;
+
+	if (is_encode_session(inst))
+		window_size = ENC_FPS_WINDOW;
+	else
+		window_size = DEC_FPS_WINDOW;
+
+	/* keep sliding window */
+	if (inst->timestamps.count > window_size) {
+		ts = msm_vidc_get_least_rank_ts(inst);
+		if (!ts) {
+			i_vpr_e(inst, "%s: least rank ts is NULL\n", __func__);
+			return -EINVAL;
+		}
+		inst->timestamps.count--;
+		list_del(&ts->sort.list);
+		msm_vidc_pool_free(inst, ts);
+	}
+
+	/* Calculate timestamp rate */
+	list_for_each_entry(ts, &inst->timestamps.list, sort.list) {
+		if (prev) {
+			if (ts->sort.val == prev->sort.val)
+				continue;
+			ts_ms += div_u64(ts->sort.val - prev->sort.val, 1000000);
+			counter++;
+		}
+		prev = ts;
+	}
+	if (ts_ms)
+		timestamp_rate = (u32)div_u64((u64)counter * 1000, ts_ms);
+
+	msm_vidc_update_cap_value(inst, TIMESTAMP_RATE, timestamp_rate << 16, __func__);
+
+	return 0;
+}
+
+struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst,
+						struct vb2_buffer *vb2)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *buf;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	buf = msm_vidc_fetch_buffer(inst, vb2);
+	if (!buf) {
+		i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__);
+		return NULL;
+	}
+
+	rc = vb2_buffer_to_driver(vb2, buf);
+	if (rc)
+		return NULL;
+
+	/* treat every buffer as deferred buffer initially */
+	buf->attr |= MSM_VIDC_ATTR_DEFERRED;
+
+	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
+		/* get a reference */
+		if (!buf->dbuf_get) {
+			buf->dmabuf = call_mem_op(core, dma_buf_get, inst, buf->fd);
+			if (!buf->dmabuf)
+				return NULL;
+			buf->dbuf_get = 1;
+		}
+	}
+
+	return buf;
+}
+
+int msm_vidc_allocate_buffers(struct msm_vidc_inst *inst,
+			      enum msm_vidc_buffer_type buf_type,
+			      u32 num_buffers)
+{
+	int rc = 0;
+	int idx = 0;
+	struct msm_vidc_buffer *buf = NULL;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	buffers = msm_vidc_get_buffers(inst, buf_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	for (idx = 0; idx < num_buffers; idx++) {
+		buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER);
+		if (!buf) {
+			i_vpr_e(inst, "%s: alloc failed\n", __func__);
+			return -EINVAL;
+		}
+		INIT_LIST_HEAD(&buf->list);
+		list_add_tail(&buf->list, &buffers->list);
+		buf->type = buf_type;
+		buf->index = idx;
+		buf->region = call_mem_op(core, buffer_region, inst, buf_type);
+	}
+	i_vpr_h(inst, "%s: allocated %d buffers for type %s\n",
+		__func__, num_buffers, buf_name(buf_type));
+
+	return rc;
+}
+
+int msm_vidc_free_buffers(struct msm_vidc_inst *inst,
+			  enum msm_vidc_buffer_type buf_type)
+{
+	int rc = 0;
+	int buf_count = 0;
+	struct msm_vidc_buffer *buf, *dummy;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	buffers = msm_vidc_get_buffers(inst, buf_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+		buf_count++;
+		print_vidc_buffer(VIDC_LOW, "low ", "free buffer", inst, buf);
+		list_del_init(&buf->list);
+		msm_vidc_pool_free(inst, buf);
+	}
+	i_vpr_h(inst, "%s: freed %d buffers for type %s\n",
+		__func__, buf_count, buf_name(buf_type));
+
+	return rc;
+}
+
+struct msm_vidc_buffer *msm_vidc_fetch_buffer(struct msm_vidc_inst *inst,
+					      struct vb2_buffer *vb2)
+
+{
+	struct msm_vidc_buffer *buf = NULL;
+	struct msm_vidc_buffers *buffers;
+	enum msm_vidc_buffer_type buf_type;
+	bool found = false;
+
+	buf_type = v4l2_type_to_driver(vb2->type, __func__);
+	if (!buf_type)
+		return NULL;
+
+	buffers = msm_vidc_get_buffers(inst, buf_type, __func__);
+	if (!buffers)
+		return NULL;
+
+	list_for_each_entry(buf, &buffers->list, list) {
+		if (buf->index == vb2->index) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		i_vpr_e(inst, "%s: buffer not found for index %d for vb2 buffer type %s\n",
+			__func__, vb2->index, v4l2_type_name(vb2->type));
+		return NULL;
+	}
+
+	return buf;
+}
+
+static bool is_single_session(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 count = 0;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry(inst, &core->instances, list)
+		count++;
+	core_unlock(core, __func__);
+
+	return count == 1;
+}
+
+void msm_vidc_allow_dcvs(struct msm_vidc_inst *inst)
+{
+	bool allow = false;
+	struct msm_vidc_core *core;
+	u32 fps;
+
+	core = inst->core;
+
+	allow = core->capabilities[DCVS].value;
+	if (!allow) {
+		i_vpr_h(inst, "%s: core doesn't support dcvs\n", __func__);
+		goto exit;
+	}
+
+	allow = !inst->decode_batch.enable;
+	if (!allow) {
+		i_vpr_h(inst, "%s: decode_batching enabled\n", __func__);
+		goto exit;
+	}
+
+	fps =  msm_vidc_get_fps(inst);
+	if (is_decode_session(inst) &&
+	    fps >= inst->capabilities[FRAME_RATE].max) {
+		allow = false;
+		i_vpr_h(inst, "%s: unsupported fps %d\n", __func__, fps);
+		goto exit;
+	}
+
+exit:
+	i_vpr_hp(inst, "%s: dcvs: %s\n", __func__, allow ? "enabled" : "disabled");
+
+	inst->power.dcvs_flags = 0;
+	inst->power.dcvs_mode = allow;
+}
+
+bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst_cap *cap;
+	struct msm_vidc_core *core;
+	bool allow = false;
+	u32 value = 0;
+
+	core = inst->core;
+	cap = &inst->capabilities[0];
+
+	allow = inst->decode_batch.enable;
+	if (!allow) {
+		i_vpr_h(inst, "%s: batching already disabled\n", __func__);
+		goto exit;
+	}
+
+	allow = core->capabilities[DECODE_BATCH].value;
+	if (!allow) {
+		i_vpr_h(inst, "%s: core doesn't support batching\n", __func__);
+		goto exit;
+	}
+
+	allow = is_single_session(inst);
+	if (!allow) {
+		i_vpr_h(inst, "%s: multiple sessions running\n", __func__);
+		goto exit;
+	}
+
+	allow = is_decode_session(inst);
+	if (!allow) {
+		i_vpr_h(inst, "%s: not a decoder session\n", __func__);
+		goto exit;
+	}
+
+	value = msm_vidc_get_fps(inst);
+	allow = value < cap[BATCH_FPS].value;
+	if (!allow) {
+		i_vpr_h(inst, "%s: unsupported fps %u, max %u\n", __func__,
+			value, cap[BATCH_FPS].value);
+		goto exit;
+	}
+
+	value = msm_vidc_get_mbs_per_frame(inst);
+	allow = value < cap[BATCH_MBPF].value;
+	if (!allow) {
+		i_vpr_h(inst, "%s: unsupported mbpf %u, max %u\n", __func__,
+			value, cap[BATCH_MBPF].value);
+		goto exit;
+	}
+
+exit:
+	i_vpr_hp(inst, "%s: batching: %s\n", __func__, allow ? "enabled" : "disabled");
+
+	return allow;
+}
+
+void msm_vidc_update_stats(struct msm_vidc_inst *inst,
+			   struct msm_vidc_buffer *buf, enum msm_vidc_debugfs_event etype)
+{
+	if ((is_decode_session(inst) && etype == MSM_VIDC_DEBUGFS_EVENT_ETB) ||
+	    (is_encode_session(inst) && etype == MSM_VIDC_DEBUGFS_EVENT_FBD))
+		inst->stats.data_size += buf->data_size;
+
+	msm_vidc_debugfs_update(inst, etype);
+}
+
+void msm_vidc_print_stats(struct msm_vidc_inst *inst)
+{
+	u32 frame_rate, operating_rate, achieved_fps, etb, ebd, ftb, fbd, dt_ms;
+	u64 bitrate_kbps = 0, time_ms = ktime_get_ns() / 1000 / 1000;
+
+	etb = inst->debug_count.etb - inst->stats.count.etb;
+	ebd = inst->debug_count.ebd - inst->stats.count.ebd;
+	ftb = inst->debug_count.ftb - inst->stats.count.ftb;
+	fbd = inst->debug_count.fbd - inst->stats.count.fbd;
+	frame_rate = inst->capabilities[FRAME_RATE].value >> 16;
+	operating_rate = inst->capabilities[OPERATING_RATE].value >> 16;
+
+	dt_ms = time_ms - inst->stats.time_ms;
+	achieved_fps = (fbd * 1000) / dt_ms;
+	bitrate_kbps = (inst->stats.data_size * 8 * 1000) / (dt_ms * 1024);
+
+	i_vpr_hs(inst,
+		 "counts (etb,ebd,ftb,fbd): %u %u %u %u (total %llu %llu %llu %llu), bps %lldKbps fps %u/s, frame rate %u, op rate %u, avg bw llcc %ukhz, avb bw ddr %ukhz, dt %ums\n",
+		 etb, ebd, ftb, fbd, inst->debug_count.etb, inst->debug_count.ebd,
+		 inst->debug_count.ftb, inst->debug_count.fbd, bitrate_kbps,
+		 achieved_fps, frame_rate, operating_rate,
+		 inst->stats.avg_bw_llcc, inst->stats.avg_bw_ddr, dt_ms);
+
+	inst->stats.count = inst->debug_count;
+	inst->stats.data_size = 0;
+	inst->stats.avg_bw_llcc = 0;
+	inst->stats.avg_bw_ddr = 0;
+	inst->stats.time_ms = time_ms;
+}
+
+void msm_vidc_print_memory_stats(struct msm_vidc_inst *inst)
+{
+	static enum msm_vidc_buffer_type buf_type_arr[8] = {
+		MSM_VIDC_BUF_BIN,
+		MSM_VIDC_BUF_ARP,
+		MSM_VIDC_BUF_COMV,
+		MSM_VIDC_BUF_NON_COMV,
+		MSM_VIDC_BUF_LINE,
+		MSM_VIDC_BUF_DPB,
+		MSM_VIDC_BUF_PERSIST,
+		MSM_VIDC_BUF_VPSS,
+	};
+	u32 count_arr[8];
+	u32 size_arr[8];
+	u32 size_kb_arr[8];
+	u64 total_size = 0;
+	struct msm_vidc_buffers *buffers;
+	int cnt;
+
+	/* reset array values */
+	memset(&count_arr, 0, sizeof(count_arr));
+	memset(&size_arr, 0, sizeof(size_arr));
+	memset(&size_kb_arr, 0, sizeof(size_kb_arr));
+
+	/* populate buffer details */
+	for (cnt = 0; cnt < 8; cnt++) {
+		buffers = msm_vidc_get_buffers(inst, buf_type_arr[cnt], __func__);
+		if (!buffers)
+			continue;
+
+		size_arr[cnt] = buffers->size;
+		count_arr[cnt] = buffers->min_count;
+		size_kb_arr[cnt] = (size_arr[cnt] * count_arr[cnt]) / 1024;
+		total_size += size_arr[cnt] * count_arr[cnt];
+	}
+
+	/* print internal memory stats */
+	i_vpr_hs(inst,
+		 "%s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) total %llu kb\n",
+		 buf_name(buf_type_arr[0]), size_kb_arr[0], size_arr[0], count_arr[0],
+		 buf_name(buf_type_arr[1]), size_kb_arr[1], size_arr[1], count_arr[1],
+		 buf_name(buf_type_arr[2]), size_kb_arr[2], size_arr[2], count_arr[2],
+		 buf_name(buf_type_arr[3]), size_kb_arr[3], size_arr[3], count_arr[3],
+		 buf_name(buf_type_arr[4]), size_kb_arr[4], size_arr[4], count_arr[4],
+		 buf_name(buf_type_arr[5]), size_kb_arr[5], size_arr[5], count_arr[5],
+		 buf_name(buf_type_arr[6]), size_kb_arr[6], size_arr[6], count_arr[6],
+		 buf_name(buf_type_arr[7]), size_kb_arr[7], size_arr[7], count_arr[7],
+		 (total_size / 1024));
+}
+
+int schedule_stats_work(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!is_stats_enabled()) {
+		i_vpr_h(inst, "%s: stats not enabled. Skip scheduling\n", __func__);
+		return 0;
+	}
+
+	/**
+	 * Hfi session is already closed and inst also going to be
+	 * closed soon. So skip scheduling new stats_work to avoid
+	 * use-after-free issues with close sequence.
+	 */
+	if (!inst->packet) {
+		i_vpr_e(inst, "skip scheduling stats_work\n");
+		return 0;
+	}
+	core = inst->core;
+	mod_delayed_work(inst->workq, &inst->stats_work,
+			 msecs_to_jiffies(core->capabilities[STATS_TIMEOUT_MS].value));
+
+	return 0;
+}
+
+int cancel_stats_work_sync(struct msm_vidc_inst *inst)
+{
+	cancel_delayed_work_sync(&inst->stats_work);
+
+	return 0;
+}
+
+void msm_vidc_stats_handler(struct work_struct *work)
+{
+	struct msm_vidc_inst *inst;
+
+	inst = container_of(work, struct msm_vidc_inst, stats_work.work);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	inst_lock(inst, __func__);
+	msm_vidc_print_stats(inst);
+	schedule_stats_work(inst);
+	inst_unlock(inst, __func__);
+
+	put_inst(inst);
+}
+
+static int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf)
+{
+	enum msm_vidc_debugfs_event etype;
+	int rc = 0;
+
+	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
+		rc = msm_vidc_process_readonly_buffers(inst, buf);
+		if (rc)
+			return rc;
+	}
+
+	print_vidc_buffer(VIDC_HIGH, "high", "qbuf", inst, buf);
+
+	rc = venus_hfi_queue_buffer(inst, buf);
+	if (rc)
+		return rc;
+
+	buf->attr &= ~MSM_VIDC_ATTR_DEFERRED;
+	buf->attr |= MSM_VIDC_ATTR_QUEUED;
+
+	if (is_input_buffer(buf->type))
+		inst->power.buffer_counter++;
+
+	if (is_input_buffer(buf->type))
+		etype = MSM_VIDC_DEBUGFS_EVENT_ETB;
+	else
+		etype = MSM_VIDC_DEBUGFS_EVENT_FTB;
+
+	msm_vidc_update_stats(inst, buf, etype);
+
+	return 0;
+}
+
+int msm_vidc_alloc_and_queue_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vdec_get_input_internal_buffers(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_vdec_release_input_internal_buffers(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_vdec_create_input_internal_buffers(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_vdec_queue_input_internal_buffers(inst);
+
+	return rc;
+}
+
+int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buf_type)
+{
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	int rc = 0;
+
+	buffers = msm_vidc_get_buffers(inst, buf_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	msm_vidc_scale_power(inst, true);
+
+	list_for_each_entry(buf, &buffers->list, list) {
+		if (!(buf->attr & MSM_VIDC_ATTR_DEFERRED))
+			continue;
+		rc = msm_vidc_queue_buffer(inst, buf);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf)
+{
+	msm_vidc_scale_power(inst, is_input_buffer(buf->type));
+
+	return msm_vidc_queue_buffer(inst, buf);
+}
+
+int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *buf = NULL;
+	struct msm_vidc_core *core = NULL;
+
+	core = inst->core;
+
+	buf = msm_vidc_get_driver_buf(inst, vb2);
+	if (!buf)
+		return -EINVAL;
+
+	rc = inst->event_handle(inst, MSM_VIDC_BUF_QUEUE, buf);
+	if (rc)
+		goto exit;
+
+exit:
+	if (rc)
+		i_vpr_e(inst, "%s: qbuf failed\n", __func__);
+	return rc;
+}
+
+int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst,
+				     struct msm_vidc_buffer *buffer)
+{
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_mem_list *mem_list;
+	struct msm_vidc_mem *mem, *mem_dummy;
+	struct msm_vidc_buffer *buf, *dummy;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (!is_internal_buffer(buffer->type)) {
+		i_vpr_e(inst, "%s: type: %s is not internal\n",
+			__func__, buf_name(buffer->type));
+		return 0;
+	}
+
+	i_vpr_h(inst, "%s: destroy: type: %8s, size: %9u, device_addr %#llx\n", __func__,
+		buf_name(buffer->type), buffer->buffer_size, buffer->device_addr);
+
+	buffers = msm_vidc_get_buffers(inst, buffer->type, __func__);
+	if (!buffers)
+		return -EINVAL;
+	mem_list = msm_vidc_get_mem_info(inst, buffer->type, __func__);
+	if (!mem_list)
+		return -EINVAL;
+
+	list_for_each_entry_safe(mem, mem_dummy, &mem_list->list, list) {
+		if (mem->dmabuf == buffer->dmabuf) {
+			call_mem_op(core, memory_unmap_free, core, mem);
+			list_del(&mem->list);
+			msm_vidc_pool_free(inst, mem);
+			break;
+		}
+	}
+
+	list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+		if (buf->dmabuf == buffer->dmabuf) {
+			list_del(&buf->list);
+			msm_vidc_pool_free(inst, buf);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst,
+				  enum msm_vidc_buffer_type buffer_type)
+{
+	u32 buf_size;
+	u32 buf_count;
+	struct msm_vidc_core *core;
+	struct msm_vidc_buffers *buffers;
+
+	core = inst->core;
+
+	buf_size = call_session_op(core, buffer_size,
+				   inst, buffer_type);
+
+	buf_count = call_session_op(core, min_count,
+				    inst, buffer_type);
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	/*
+	 * In a usecase when film grain is initially present, dpb buffers
+	 * are allocated and in the middle of the session, if film grain
+	 * is disabled, then dpb internal buffers should be destroyed.
+	 * When film grain is disabled, buffer_size op call returns 0.
+	 * To ensure buffers->reuse is set to false, add check to detect
+	 * if buf_size has become zero. Do the same for buf_count as well.
+	 */
+	if (buf_size && buf_size <= buffers->size &&
+	    buf_count && buf_count <= buffers->min_count) {
+		buffers->reuse = true;
+	} else {
+		buffers->reuse = false;
+		buffers->size = buf_size;
+		buffers->min_count = buf_count;
+	}
+	return 0;
+}
+
+int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
+				    enum msm_vidc_buffer_type buffer_type, u32 index)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_mem_list *mem_list;
+	struct msm_vidc_buffer *buffer;
+	struct msm_vidc_mem *mem;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+	if (!is_internal_buffer(buffer_type)) {
+		i_vpr_e(inst, "%s: type %s is not internal\n",
+			__func__, buf_name(buffer_type));
+		return 0;
+	}
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+	mem_list = msm_vidc_get_mem_info(inst, buffer_type, __func__);
+	if (!mem_list)
+		return -EINVAL;
+
+	if (!buffers->size)
+		return 0;
+
+	buffer = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER);
+	if (!buffer) {
+		i_vpr_e(inst, "%s: buf alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&buffer->list);
+	buffer->type = buffer_type;
+	buffer->index = index;
+	buffer->buffer_size = buffers->size;
+	list_add_tail(&buffer->list, &buffers->list);
+
+	mem = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_ALLOC_MAP);
+	if (!mem) {
+		i_vpr_e(inst, "%s: mem poo alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&mem->list);
+	mem->type = buffer_type;
+	mem->region = call_mem_op(core, buffer_region, inst, buffer_type);
+	mem->size = buffer->buffer_size;
+	mem->secure = is_secure_region(mem->region);
+	rc = call_mem_op(core, memory_alloc_map, core, mem);
+	if (rc)
+		return -ENOMEM;
+	list_add_tail(&mem->list, &mem_list->list);
+
+	buffer->dmabuf = mem->dmabuf;
+	buffer->device_addr = mem->device_addr;
+	buffer->region = mem->region;
+	i_vpr_h(inst, "%s: create: type: %8s, size: %9u, device_addr %#llx\n", __func__,
+		buf_name(buffer_type), buffers->size, buffer->device_addr);
+
+	return 0;
+}
+
+int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
+				     enum msm_vidc_buffer_type buffer_type)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	int i;
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buffers->reuse) {
+		i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__, buf_name(buffer_type));
+		return 0;
+	}
+
+	for (i = 0; i < buffers->min_count; i++) {
+		rc = msm_vidc_create_internal_buffer(inst, buffer_type, i);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst,
+				    enum msm_vidc_buffer_type buffer_type)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buffer, *dummy;
+
+	if (!is_internal_buffer(buffer_type)) {
+		i_vpr_e(inst, "%s: %s is not internal\n", __func__, buf_name(buffer_type));
+		return 0;
+	}
+
+	/*
+	 * Set HFI_PROP_COMV_BUFFER_COUNT to firmware even if COMV buffer
+	 * is reused.
+	 */
+	if (is_decode_session(inst) && buffer_type == MSM_VIDC_BUF_COMV) {
+		rc = msm_vdec_set_num_comv(inst);
+		if (rc)
+			return rc;
+	}
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
+		/* do not queue pending release buffers */
+		if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		/* do not queue already queued buffers */
+		if (buffer->attr & MSM_VIDC_ATTR_QUEUED)
+			continue;
+		rc = venus_hfi_queue_buffer(inst, buffer);
+		if (rc)
+			return rc;
+		/* mark queued */
+		buffer->attr |= MSM_VIDC_ATTR_QUEUED;
+
+		i_vpr_h(inst, "%s: queue: type: %8s, size: %9u, device_addr %#llx\n", __func__,
+			buf_name(buffer->type), buffer->buffer_size, buffer->device_addr);
+	}
+
+	return 0;
+}
+
+int msm_vidc_alloc_and_queue_session_int_bufs(struct msm_vidc_inst *inst,
+					      enum msm_vidc_buffer_type buffer_type)
+{
+	int rc = 0;
+
+	if (buffer_type != MSM_VIDC_BUF_ARP &&
+	    buffer_type != MSM_VIDC_BUF_PERSIST) {
+		i_vpr_e(inst, "%s: invalid buffer type: %s\n",
+			__func__, buf_name(buffer_type));
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = msm_vidc_get_internal_buffers(inst, buffer_type);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_create_internal_buffers(inst, buffer_type);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_queue_internal_buffers(inst, buffer_type);
+	if (rc)
+		goto exit;
+
+exit:
+	return rc;
+}
+
+int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
+				      enum msm_vidc_buffer_type buffer_type)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buffer, *dummy;
+
+	if (!is_internal_buffer(buffer_type)) {
+		i_vpr_e(inst, "%s: %s is not internal\n",
+			__func__, buf_name(buffer_type));
+		return 0;
+	}
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buffers->reuse) {
+		i_vpr_l(inst, "%s: reuse enabled for %s buf\n",
+			__func__, buf_name(buffer_type));
+		return 0;
+	}
+
+	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
+		/* do not release already pending release buffers */
+		if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		/* release only queued buffers */
+		if (!(buffer->attr & MSM_VIDC_ATTR_QUEUED))
+			continue;
+		rc = venus_hfi_release_buffer(inst, buffer);
+		if (rc)
+			return rc;
+		/* mark pending release */
+		buffer->attr |= MSM_VIDC_ATTR_PENDING_RELEASE;
+
+		i_vpr_h(inst, "%s: release: type: %8s, size: %9u, device_addr %#llx\n", __func__,
+			buf_name(buffer->type), buffer->buffer_size, buffer->device_addr);
+	}
+
+	return 0;
+}
+
+int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
+			     struct msm_vidc_buffer *buf)
+{
+	int type, port, state;
+	struct vb2_queue *q;
+	struct vb2_buffer *vb2;
+	struct vb2_v4l2_buffer *vbuf;
+	bool found;
+
+	type = v4l2_type_from_driver(buf->type, __func__);
+	if (!type)
+		return -EINVAL;
+	port = v4l2_type_to_driver_port(inst, type, __func__);
+	if (port < 0)
+		return -EINVAL;
+
+	q = inst->bufq[port].vb2q;
+	if (!q->streaming) {
+		i_vpr_e(inst, "%s: port %d is not streaming\n",
+			__func__, port);
+		return -EINVAL;
+	}
+
+	found = false;
+	list_for_each_entry(vb2, &q->queued_list, queued_entry) {
+		if (vb2->state != VB2_BUF_STATE_ACTIVE)
+			continue;
+		if (vb2->index == buf->index) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		print_vidc_buffer(VIDC_ERR, "err ", "vb2 not found for", inst, buf);
+		return -EINVAL;
+	}
+	/**
+	 * v4l2 clears buffer state related flags. For driver errors
+	 * send state as error to avoid skipping V4L2_BUF_FLAG_ERROR
+	 * flag at v4l2 side.
+	 */
+	if (buf->flags & MSM_VIDC_BUF_FLAG_ERROR)
+		state = VB2_BUF_STATE_ERROR;
+	else
+		state = VB2_BUF_STATE_DONE;
+
+	vbuf = to_vb2_v4l2_buffer(vb2);
+	vbuf->flags = buf->flags;
+	vb2->timestamp = buf->timestamp;
+	vb2->planes[0].bytesused = buf->data_size + vb2->planes[0].data_offset;
+	vb2_buffer_done(vb2, state);
+
+	return 0;
+}
+
+int msm_vidc_v4l2_fh_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int index;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	/* do not init, if already inited */
+	if (inst->fh.vdev) {
+		i_vpr_e(inst, "%s: already inited\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst))
+		index = 0;
+	else if (is_encode_session(inst))
+		index = 1;
+	else
+		return -EINVAL;
+
+	v4l2_fh_init(&inst->fh, &core->vdev[index].vdev);
+	inst->fh.ctrl_handler = &inst->ctrl_handler;
+	v4l2_fh_add(&inst->fh);
+
+	return rc;
+}
+
+int msm_vidc_v4l2_fh_deinit(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	/* do not deinit, if not already inited */
+	if (!inst->fh.vdev) {
+		i_vpr_h(inst, "%s: already not inited\n", __func__);
+		return 0;
+	}
+
+	v4l2_fh_del(&inst->fh);
+	inst->fh.ctrl_handler = NULL;
+	v4l2_fh_exit(&inst->fh);
+
+	return rc;
+}
+
+static int vb2q_init(struct msm_vidc_inst *inst,
+		     struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	q->type = type;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	q->ops = core->vb2_ops;
+	q->mem_ops = core->vb2_mem_ops;
+	q->drv_priv = inst;
+	q->copy_timestamp = 1;
+	rc = vb2_queue_init(q);
+	if (rc)
+		i_vpr_e(inst, "%s: vb2_queue_init failed for type %d\n",
+			__func__, type);
+	return rc;
+}
+
+static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+			  struct vb2_queue *dst_vq)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = priv;
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core || !src_vq || !dst_vq) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	src_vq->lock = &inst->ctx_q_lock;
+	src_vq->dev = &core->pdev->dev;
+	rc = vb2q_init(inst, src_vq, INPUT_MPLANE);
+	if (rc)
+		goto fail_input_vb2q_init;
+	inst->bufq[INPUT_PORT].vb2q = src_vq;
+
+	dst_vq->lock = src_vq->lock;
+	dst_vq->dev = &core->pdev->dev;
+	rc = vb2q_init(inst, dst_vq, OUTPUT_MPLANE);
+	if (rc)
+		goto fail_out_vb2q_init;
+	inst->bufq[OUTPUT_PORT].vb2q = dst_vq;
+	return rc;
+
+fail_out_vb2q_init:
+	vb2_queue_release(inst->bufq[INPUT_PORT].vb2q);
+fail_input_vb2q_init:
+	return rc;
+}
+
+int msm_vidc_vb2_queue_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (inst->m2m_dev) {
+		i_vpr_e(inst, "%s: vb2q already inited\n", __func__);
+		return -EINVAL;
+	}
+
+	inst->m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
+	if (IS_ERR(inst->m2m_dev)) {
+		i_vpr_e(inst, "%s: failed to initialize v4l2 m2m device\n", __func__);
+		rc = PTR_ERR(inst->m2m_dev);
+		goto fail_m2m_init;
+	}
+
+	/* v4l2_m2m_ctx_init will do input & output queues initialization */
+	inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init);
+	if (!inst->m2m_ctx) {
+		rc = -EINVAL;
+		i_vpr_e(inst, "%s: v4l2_m2m_ctx_init failed\n", __func__);
+		goto fail_m2m_ctx_init;
+	}
+	inst->fh.m2m_ctx = inst->m2m_ctx;
+
+	return 0;
+
+fail_m2m_ctx_init:
+	v4l2_m2m_release(inst->m2m_dev);
+	inst->m2m_dev = NULL;
+fail_m2m_init:
+	return rc;
+}
+
+int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst->m2m_dev) {
+		i_vpr_h(inst, "%s: vb2q already deinited\n", __func__);
+		return 0;
+	}
+
+	/*
+	 * vb2_queue_release() for input and output queues
+	 * is called from v4l2_m2m_ctx_release()
+	 */
+	v4l2_m2m_ctx_release(inst->m2m_ctx);
+	inst->m2m_ctx = NULL;
+	inst->bufq[OUTPUT_PORT].vb2q = NULL;
+	inst->bufq[INPUT_PORT].vb2q = NULL;
+	v4l2_m2m_release(inst->m2m_dev);
+	inst->m2m_dev = NULL;
+
+	return rc;
+}
+
+int msm_vidc_add_session(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_inst *i;
+	struct msm_vidc_core *core;
+	u32 count = 0;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	if (core->state != MSM_VIDC_CORE_INIT) {
+		i_vpr_e(inst, "%s: invalid state %s\n",
+			__func__, core_state_name(core->state));
+		rc = -EINVAL;
+		goto unlock;
+	}
+	list_for_each_entry(i, &core->instances, list)
+		count++;
+
+	if (count < core->capabilities[MAX_SESSION_COUNT].value) {
+		list_add_tail(&inst->list, &core->instances);
+	} else {
+		i_vpr_e(inst, "%s: max limit %d already running %d sessions\n",
+			__func__, core->capabilities[MAX_SESSION_COUNT].value, count);
+		rc = -EAGAIN;
+	}
+unlock:
+	core_unlock(core, __func__);
+
+	return rc;
+}
+
+int msm_vidc_remove_session(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst *i, *temp;
+	struct msm_vidc_core *core;
+	u32 count = 0;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry_safe(i, temp, &core->instances, list) {
+		if (i->session_id == inst->session_id) {
+			list_move_tail(&i->list, &core->dangling_instances);
+			i_vpr_h(inst, "%s: removed session %#x\n",
+				__func__, i->session_id);
+		}
+	}
+	list_for_each_entry(i, &core->instances, list)
+		count++;
+	i_vpr_h(inst, "%s: remaining sessions %d\n", __func__, count);
+	core_unlock(core, __func__);
+
+	return 0;
+}
+
+int msm_vidc_remove_dangling_session(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst *i, *temp;
+	struct msm_vidc_core *core;
+	u32 count = 0, dcount = 0;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry_safe(i, temp, &core->dangling_instances, list) {
+		if (i->session_id == inst->session_id) {
+			list_del_init(&i->list);
+			i_vpr_h(inst, "%s: removed dangling session %#x\n",
+				__func__, i->session_id);
+			break;
+		}
+	}
+	list_for_each_entry(i, &core->instances, list)
+		count++;
+	list_for_each_entry(i, &core->dangling_instances, list)
+		dcount++;
+	i_vpr_h(inst, "%s: remaining sessions. active %d, dangling %d\n",
+		__func__, count, dcount);
+	core_unlock(core, __func__);
+
+	return 0;
+}
+
+int msm_vidc_session_open(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	inst->packet_size = 4096;
+
+	inst->packet = vzalloc(inst->packet_size);
+	if (!inst->packet) {
+		i_vpr_e(inst, "%s: allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = venus_hfi_session_open(inst);
+	if (rc)
+		goto error;
+
+	return 0;
+error:
+	i_vpr_e(inst, "%s(): session open failed\n", __func__);
+	vfree(inst->packet);
+	inst->packet = NULL;
+	return rc;
+}
+
+int msm_vidc_session_set_codec(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = venus_hfi_session_set_codec(inst);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 default_header = false;
+
+	default_header = inst->capabilities[DEFAULT_HEADER].value;
+	i_vpr_h(inst, "%s: default header: %d", __func__, default_header);
+	rc = venus_hfi_session_property(inst,
+					HFI_PROP_DEC_DEFAULT_HEADER,
+					HFI_HOST_FLAGS_NONE,
+					get_hfi_port(inst, INPUT_PORT),
+					HFI_PAYLOAD_U32,
+					&default_header,
+			sizeof(u32));
+	if (rc)
+		i_vpr_e(inst, "%s: set property failed\n", __func__);
+	return rc;
+}
+
+int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
+			       enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	int count = 0;
+	struct msm_vidc_core *core;
+	enum signal_session_response signal_type;
+	enum msm_vidc_buffer_type buffer_type;
+	u32 hw_response_timeout_val;
+
+	if (port == INPUT_PORT) {
+		signal_type = SIGNAL_CMD_STOP_INPUT;
+		buffer_type = MSM_VIDC_BUF_INPUT;
+	} else if (port == OUTPUT_PORT) {
+		signal_type = SIGNAL_CMD_STOP_OUTPUT;
+		buffer_type = MSM_VIDC_BUF_OUTPUT;
+	} else {
+		i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_stop(inst, port);
+	if (rc)
+		goto error;
+
+	core = inst->core;
+	hw_response_timeout_val = core->capabilities[HW_RESPONSE_TIMEOUT].value;
+	i_vpr_h(inst, "%s: wait on port: %d for time: %d ms\n",
+		__func__, port, hw_response_timeout_val);
+	inst_unlock(inst, __func__);
+	rc = wait_for_completion_timeout(&inst->completions[signal_type],
+					 msecs_to_jiffies(hw_response_timeout_val));
+	if (!rc) {
+		i_vpr_e(inst, "%s: session stop timed out for port: %d\n",
+			__func__, port);
+		rc = -ETIMEDOUT;
+		msm_vidc_inst_timeout(inst);
+	} else {
+		rc = 0;
+	}
+	inst_lock(inst, __func__);
+
+	if (rc)
+		goto error;
+
+	if (port == INPUT_PORT) {
+		/* flush input timer list */
+		msm_vidc_flush_input_timer(inst);
+	}
+
+	/* no more queued buffers after streamoff */
+	count = msm_vidc_num_buffers(inst, buffer_type, MSM_VIDC_ATTR_QUEUED);
+	if (!count) {
+		i_vpr_h(inst, "%s: stop successful on port: %d\n",
+			__func__, port);
+	} else {
+		i_vpr_e(inst,
+			"%s: %d buffers pending with firmware on port: %d\n",
+			__func__, count, port);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = msm_vidc_state_change_streamoff(inst, port);
+	if (rc)
+		goto error;
+
+	/* flush deferred buffers */
+	msm_vidc_flush_buffers(inst, buffer_type);
+	msm_vidc_flush_read_only_buffers(inst, buffer_type);
+	return 0;
+
+error:
+	msm_vidc_kill_session(inst);
+	msm_vidc_flush_buffers(inst, buffer_type);
+	msm_vidc_flush_read_only_buffers(inst, buffer_type);
+	return rc;
+}
+
+int msm_vidc_session_close(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	bool wait_for_response;
+	u32 hw_response_timeout_val;
+
+	core = inst->core;
+	hw_response_timeout_val = core->capabilities[HW_RESPONSE_TIMEOUT].value;
+	wait_for_response = true;
+	rc = venus_hfi_session_close(inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: session close cmd failed\n", __func__);
+		wait_for_response = false;
+	}
+
+	/* we are not supposed to send any more commands after close */
+	i_vpr_h(inst, "%s: free session packet data\n", __func__);
+	vfree(inst->packet);
+	inst->packet = NULL;
+
+	if (wait_for_response) {
+		i_vpr_h(inst, "%s: wait on close for time: %d ms\n",
+			__func__, hw_response_timeout_val);
+		inst_unlock(inst, __func__);
+		rc = wait_for_completion_timeout(&inst->completions[SIGNAL_CMD_CLOSE],
+						 msecs_to_jiffies(hw_response_timeout_val));
+		if (!rc) {
+			i_vpr_e(inst, "%s: session close timed out\n", __func__);
+			rc = -ETIMEDOUT;
+			msm_vidc_inst_timeout(inst);
+		} else {
+			rc = 0;
+			i_vpr_h(inst, "%s: close successful\n", __func__);
+		}
+		inst_lock(inst, __func__);
+	}
+
+	return rc;
+}
+
+int msm_vidc_kill_session(struct msm_vidc_inst *inst)
+{
+	if (!inst->session_id) {
+		i_vpr_e(inst, "%s: already killed\n", __func__);
+		return 0;
+	}
+
+	i_vpr_e(inst, "%s: killing session\n", __func__);
+	msm_vidc_session_close(inst);
+	msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+
+	return 0;
+}
+
+int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst)
+{
+	int i;
+	u32 codecs_count = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	codecs_count = core->enc_codecs_count + core->dec_codecs_count;
+
+	for (i = 0; i < codecs_count; i++) {
+		if (core->inst_caps[i].domain == inst->domain &&
+		    core->inst_caps[i].codec == inst->codec) {
+			i_vpr_h(inst,
+				"%s: copied capabilities with %#x codec, %#x domain\n",
+				__func__, inst->codec, inst->domain);
+			memcpy(&inst->capabilities[0], &core->inst_caps[i].cap[0],
+			       (INST_CAP_MAX + 1) * sizeof(struct msm_vidc_inst_cap));
+		}
+	}
+
+	return 0;
+}
+
+int msm_vidc_init_core_caps(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	int i, num_platform_caps;
+	struct msm_platform_core_capability *platform_data;
+
+	platform_data = core->platform->data.core_data;
+	if (!platform_data) {
+		d_vpr_e("%s: platform core data is NULL\n",
+			__func__);
+			rc = -EINVAL;
+			goto exit;
+	}
+
+	num_platform_caps = core->platform->data.core_data_size;
+
+	/* loop over platform caps */
+	for (i = 0; i < num_platform_caps && i < CORE_CAP_MAX; i++) {
+		core->capabilities[platform_data[i].type].type = platform_data[i].type;
+		core->capabilities[platform_data[i].type].value = platform_data[i].value;
+	}
+
+exit:
+	return rc;
+}
+
+static int update_inst_capability(struct msm_platform_inst_capability *in,
+				  struct msm_vidc_inst_capability *capability)
+{
+	if (!in || !capability) {
+		d_vpr_e("%s: invalid params %pK %pK\n",
+			__func__, in, capability);
+		return -EINVAL;
+	}
+	if (in->cap_id >= INST_CAP_MAX) {
+		d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id);
+		return -EINVAL;
+	}
+
+	capability->cap[in->cap_id].cap_id = in->cap_id;
+	capability->cap[in->cap_id].min = in->min;
+	capability->cap[in->cap_id].max = in->max;
+	capability->cap[in->cap_id].step_or_mask = in->step_or_mask;
+	capability->cap[in->cap_id].value = in->value;
+	capability->cap[in->cap_id].flags = in->flags;
+	capability->cap[in->cap_id].v4l2_id = in->v4l2_id;
+	capability->cap[in->cap_id].hfi_id = in->hfi_id;
+
+	return 0;
+}
+
+static int update_inst_cap_dependency(struct msm_platform_inst_cap_dependency *in,
+				      struct msm_vidc_inst_capability *capability)
+{
+	if (!in || !capability) {
+		d_vpr_e("%s: invalid params %pK %pK\n",
+			__func__, in, capability);
+		return -EINVAL;
+	}
+	if (in->cap_id >= INST_CAP_MAX) {
+		d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id);
+		return -EINVAL;
+	}
+
+	if (capability->cap[in->cap_id].cap_id != in->cap_id) {
+		d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id);
+		return -EINVAL;
+	}
+
+	memcpy(capability->cap[in->cap_id].children, in->children,
+	       sizeof(capability->cap[in->cap_id].children));
+	capability->cap[in->cap_id].adjust = in->adjust;
+	capability->cap[in->cap_id].set = in->set;
+
+	return 0;
+}
+
+int msm_vidc_init_instance_caps(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u8 enc_valid_codecs, dec_valid_codecs;
+	u8 count_bits, codecs_count = 0;
+	u8 enc_codecs_count = 0, dec_codecs_count = 0;
+	int i, j, check_bit;
+	int num_platform_cap_data, num_platform_cap_dependency_data;
+	struct msm_platform_inst_capability *platform_cap_data = NULL;
+	struct msm_platform_inst_cap_dependency *platform_cap_dependency_data = NULL;
+
+	platform_cap_data = core->platform->data.inst_cap_data;
+	if (!platform_cap_data) {
+		d_vpr_e("%s: platform instance cap data is NULL\n",
+			__func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	platform_cap_dependency_data = core->platform->data.inst_cap_dependency_data;
+	if (!platform_cap_dependency_data) {
+		d_vpr_e("%s: platform instance cap dependency data is NULL\n",
+			__func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	enc_valid_codecs = core->capabilities[ENC_CODECS].value;
+	count_bits = enc_valid_codecs;
+	COUNT_BITS(count_bits, enc_codecs_count);
+	core->enc_codecs_count = enc_codecs_count;
+
+	dec_valid_codecs = core->capabilities[DEC_CODECS].value;
+	count_bits = dec_valid_codecs;
+	COUNT_BITS(count_bits, dec_codecs_count);
+	core->dec_codecs_count = dec_codecs_count;
+
+	codecs_count = enc_codecs_count + dec_codecs_count;
+	core->inst_caps = devm_kzalloc(&core->pdev->dev,
+				       codecs_count * sizeof(struct msm_vidc_inst_capability),
+				       GFP_KERNEL);
+	if (!core->inst_caps) {
+		d_vpr_e("%s: failed to alloc memory for instance caps\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	check_bit = 0;
+	/* determine codecs for enc domain */
+	for (i = 0; i < enc_codecs_count; i++) {
+		while (check_bit < (sizeof(enc_valid_codecs) * 8)) {
+			if (enc_valid_codecs & BIT(check_bit)) {
+				core->inst_caps[i].domain = MSM_VIDC_ENCODER;
+				core->inst_caps[i].codec = enc_valid_codecs &
+						BIT(check_bit);
+				check_bit++;
+				break;
+			}
+			check_bit++;
+		}
+	}
+
+	/* reset checkbit to check from 0th bit of decoder codecs set bits*/
+	check_bit = 0;
+	/* determine codecs for dec domain */
+	for (; i < codecs_count; i++) {
+		while (check_bit < (sizeof(dec_valid_codecs) * 8)) {
+			if (dec_valid_codecs & BIT(check_bit)) {
+				core->inst_caps[i].domain = MSM_VIDC_DECODER;
+				core->inst_caps[i].codec = dec_valid_codecs &
+						BIT(check_bit);
+				check_bit++;
+				break;
+			}
+			check_bit++;
+		}
+	}
+
+	num_platform_cap_data = core->platform->data.inst_cap_data_size;
+	num_platform_cap_dependency_data = core->platform->data.inst_cap_dependency_data_size;
+	d_vpr_h("%s: num caps %d, dependency %d\n", __func__,
+		num_platform_cap_data, num_platform_cap_dependency_data);
+
+	/* loop over each platform capability */
+	for (i = 0; i < num_platform_cap_data; i++) {
+		/* select matching core codec and update it */
+		for (j = 0; j < codecs_count; j++) {
+			if ((platform_cap_data[i].domain &
+				core->inst_caps[j].domain) &&
+				(platform_cap_data[i].codec &
+				core->inst_caps[j].codec)) {
+				/* update core capability */
+				rc = update_inst_capability(&platform_cap_data[i],
+							    &core->inst_caps[j]);
+				if (rc)
+					return rc;
+			}
+		}
+	}
+
+	/* loop over each platform dependency capability */
+	for (i = 0; i < num_platform_cap_dependency_data; i++) {
+		/* select matching core codec and update it */
+		for (j = 0; j < codecs_count; j++) {
+			if ((platform_cap_dependency_data[i].domain &
+				core->inst_caps[j].domain) &&
+				(platform_cap_dependency_data[i].codec &
+				core->inst_caps[j].codec)) {
+				/* update core dependency capability */
+				rc = update_inst_cap_dependency(&platform_cap_dependency_data[i],
+								&core->inst_caps[j]);
+				if (rc)
+					return rc;
+			}
+		}
+	}
+
+error:
+	return rc;
+}
+
+int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst, *dummy;
+	enum msm_vidc_allow allow;
+
+	rc = __strict_check(core, __func__);
+	if (rc) {
+		d_vpr_e("%s(): core was not locked\n", __func__);
+		return rc;
+	}
+
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
+		return 0;
+
+	/* print error for state change not allowed case */
+	allow = msm_vidc_allow_core_state_change(core, MSM_VIDC_CORE_DEINIT);
+	if (allow != MSM_VIDC_ALLOW)
+		d_vpr_e("%s: %s core state change %s -> %s\n", __func__,
+			allow_name(allow), core_state_name(core->state),
+			core_state_name(MSM_VIDC_CORE_DEINIT));
+
+	if (force) {
+		d_vpr_e("%s(): force deinit core\n", __func__);
+	} else {
+		/* in normal case, deinit core only if no session present */
+		if (!list_empty(&core->instances)) {
+			d_vpr_h("%s(): skip deinit\n", __func__);
+			return 0;
+		}
+		d_vpr_h("%s(): deinit core\n", __func__);
+	}
+
+	venus_hfi_core_deinit(core, force);
+
+	/* unlink all sessions from core, if any */
+	list_for_each_entry_safe(inst, dummy, &core->instances, list) {
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		list_move_tail(&inst->list, &core->dangling_instances);
+	}
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
+
+	return rc;
+}
+
+int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force)
+{
+	int rc = 0;
+
+	core_lock(core, __func__);
+	rc = msm_vidc_core_deinit_locked(core, force);
+	core_unlock(core, __func__);
+
+	return rc;
+}
+
+int msm_vidc_core_init_wait(struct msm_vidc_core *core)
+{
+	const int interval = 10;
+	int max_tries, count = 0, rc = 0;
+
+	core_lock(core, __func__);
+	if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
+		rc = 0;
+		goto unlock;
+	} else if (is_core_state(core, MSM_VIDC_CORE_DEINIT) ||
+		   is_core_state(core, MSM_VIDC_CORE_ERROR)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	d_vpr_h("%s(): waiting for state change\n", __func__);
+	max_tries = core->capabilities[HW_RESPONSE_TIMEOUT].value / interval;
+	while (count < max_tries) {
+		if (core->state != MSM_VIDC_CORE_INIT_WAIT)
+			break;
+
+		core_unlock(core, __func__);
+		msleep_interruptible(interval);
+		core_lock(core, __func__);
+		count++;
+	}
+	d_vpr_h("%s: state %s, interval %u, count %u, max_tries %u\n", __func__,
+		core_state_name(core->state), interval, count, max_tries);
+
+	if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
+		d_vpr_h("%s: sys init successful\n", __func__);
+		rc = 0;
+		goto unlock;
+	} else if (is_core_state(core, MSM_VIDC_CORE_INIT_WAIT)) {
+		d_vpr_h("%s: sys init wait timedout. state %s\n",
+			__func__, core_state_name(core->state));
+		msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__);
+		/* mark video hw unresponsive */
+		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE,
+					       __func__);
+		/* core deinit to handle error */
+		msm_vidc_core_deinit_locked(core, true);
+		rc = -EINVAL;
+		goto unlock;
+	} else {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		rc = -EINVAL;
+		goto unlock;
+	}
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int msm_vidc_core_init(struct msm_vidc_core *core)
+{
+	enum msm_vidc_allow allow;
+	int rc = 0;
+
+	core_lock(core, __func__);
+	if (core_in_valid_state(core)) {
+		goto unlock;
+	} else if (is_core_state(core, MSM_VIDC_CORE_ERROR)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	/* print error for state change not allowed case */
+	allow = msm_vidc_allow_core_state_change(core, MSM_VIDC_CORE_INIT_WAIT);
+	if (allow != MSM_VIDC_ALLOW)
+		d_vpr_e("%s: %s core state change %s -> %s\n", __func__,
+			allow_name(allow), core_state_name(core->state),
+			core_state_name(MSM_VIDC_CORE_INIT_WAIT));
+
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT_WAIT, __func__);
+	/* clear PM suspend from core sub_state */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT, 0, __func__);
+
+	rc = venus_hfi_core_init(core);
+	if (rc) {
+		msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__);
+		d_vpr_e("%s: core init failed\n", __func__);
+		/* do core deinit to handle error */
+		msm_vidc_core_deinit_locked(core, true);
+		goto unlock;
+	}
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int msm_vidc_inst_timeout(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *instance;
+	bool found;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	/*
+	 * All sessions will be removed from core list in core deinit,
+	 * do not deinit core from a session which is not present in
+	 * core list.
+	 */
+	found = false;
+	list_for_each_entry(instance, &core->instances, list) {
+		if (instance == inst) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		i_vpr_e(inst,
+			"%s: session not available in core list\n", __func__);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	/* mark video hw unresponsive */
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__);
+	msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE,
+				       __func__);
+
+	/* call core deinit for a valid instance timeout case */
+	msm_vidc_core_deinit_locked(core, true);
+
+unlock:
+	core_unlock(core, __func__);
+
+	return rc;
+}
+
+int msm_vidc_print_buffer_info(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_buffers *buffers;
+	int i;
+
+	/* Print buffer details */
+	for (i = 1; i < ARRAY_SIZE(buf_type_name_arr); i++) {
+		buffers = msm_vidc_get_buffers(inst, i, __func__);
+		if (!buffers)
+			continue;
+
+		i_vpr_h(inst,
+			"buf: type: %15s, min %2d, extra %2d, actual %2d, size %9u, reuse %d\n",
+			buf_name(i), buffers->min_count,
+			buffers->extra_count, buffers->actual_count,
+			buffers->size, buffers->reuse);
+	}
+
+	return 0;
+}
+
+int msm_vidc_print_inst_info(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	enum msm_vidc_port_type port;
+	bool is_decode;
+	u32 bit_depth, bit_rate, frame_rate, width, height;
+	struct dma_buf *dbuf;
+	struct inode *f_inode;
+	unsigned long inode_num = 0;
+	long ref_count = -1;
+	int i = 0;
+
+	is_decode = is_decode_session(inst);
+	port = is_decode ? INPUT_PORT : OUTPUT_PORT;
+	width = inst->fmts[port].fmt.pix_mp.width;
+	height = inst->fmts[port].fmt.pix_mp.height;
+	bit_depth = inst->capabilities[BIT_DEPTH].value & 0xFFFF;
+	bit_rate = inst->capabilities[BIT_RATE].value;
+	frame_rate = inst->capabilities[FRAME_RATE].value >> 16;
+
+	i_vpr_e(inst, "%s session, HxW: %d x %d, fps: %d, bitrate: %d, bit-depth: %d\n",
+		is_decode ? "Decode" : "Encode",
+		height, width,
+		frame_rate, bit_rate, bit_depth);
+
+	/* Print buffer details */
+	for (i = 1; i < ARRAY_SIZE(buf_type_name_arr); i++) {
+		buffers = msm_vidc_get_buffers(inst, i, __func__);
+		if (!buffers)
+			continue;
+
+		i_vpr_e(inst, "count: type: %11s, min: %2d, extra: %2d, actual: %2d\n",
+			buf_name(i), buffers->min_count,
+			buffers->extra_count, buffers->actual_count);
+
+		list_for_each_entry(buf, &buffers->list, list) {
+			if (!buf->dmabuf)
+				continue;
+			dbuf = (struct dma_buf *)buf->dmabuf;
+			if (dbuf && dbuf->file) {
+				f_inode = file_inode(dbuf->file);
+				if (f_inode) {
+					inode_num = f_inode->i_ino;
+					ref_count = file_count(dbuf->file);
+				}
+			}
+			i_vpr_e(inst,
+				"buf: type: %11s, index: %2d, fd: %4d, size: %9u, off: %8u, filled: %9u, daddr: %#llx, inode: %8lu, ref: %2ld, flags: %8x, ts: %16lld, attr: %8x\n",
+				buf_name(i), buf->index, buf->fd, buf->buffer_size,
+				buf->data_offset, buf->data_size, buf->device_addr,
+				inode_num, ref_count, buf->flags, buf->timestamp, buf->attr);
+		}
+	}
+
+	return 0;
+}
+
+void msm_vidc_print_core_info(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_inst *instances[MAX_SUPPORTED_INSTANCES];
+	s32 num_instances = 0;
+
+	core_lock(core, __func__);
+	list_for_each_entry(inst, &core->instances, list)
+		instances[num_instances++] = inst;
+	core_unlock(core, __func__);
+
+	while (num_instances--) {
+		inst = instances[num_instances];
+		inst = get_inst_ref(core, inst);
+		if (!inst)
+			continue;
+		inst_lock(inst, __func__);
+		msm_vidc_print_inst_info(inst);
+		inst_unlock(inst, __func__);
+		put_inst(inst);
+	}
+}
+
+int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
+				struct device *dev, unsigned long iova,
+				int flags, void *data)
+{
+	struct msm_vidc_core *core = data;
+
+	if (is_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT)) {
+		if (core->capabilities[NON_FATAL_FAULTS].value) {
+			dprintk_ratelimit(VIDC_ERR, "err ",
+					  "%s: non-fatal pagefault address: %lx\n",
+					  __func__, iova);
+			return 0;
+		}
+	}
+
+	d_vpr_e(FMT_STRING_FAULT_HANDLER, __func__, iova);
+
+	/* mark smmu fault as handled */
+	core_lock(core, __func__);
+	msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PAGE_FAULT, __func__);
+	core_unlock(core, __func__);
+
+	msm_vidc_print_core_info(core);
+	/*
+	 * Return -ENOSYS to elicit the default behaviour of smmu driver.
+	 * If we return -ENOSYS, then smmu driver assumes page fault handler
+	 * is not installed and prints a list of useful debug information like
+	 * FAR, SID etc. This information is not printed if we return 0.
+	 */
+	return 0;
+}
+
+void msm_vidc_fw_unload_handler(struct work_struct *work)
+{
+	struct msm_vidc_core *core = NULL;
+	int rc = 0;
+
+	core = container_of(work, struct msm_vidc_core, fw_unload_work.work);
+
+	d_vpr_h("%s: deinitializing video core\n", __func__);
+	rc = msm_vidc_core_deinit(core, false);
+	if (rc)
+		d_vpr_e("%s: Failed to deinit core\n", __func__);
+}
+
+void msm_vidc_batch_handler(struct work_struct *work)
+{
+	struct msm_vidc_inst *inst;
+	struct msm_vidc_core *core;
+	int rc = 0;
+
+	inst = container_of(work, struct msm_vidc_inst, decode_batch.work.work);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	core = inst->core;
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: failled. Session error\n", __func__);
+		goto exit;
+	}
+
+	if (is_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND)) {
+		i_vpr_h(inst, "%s: device in pm suspend state\n", __func__);
+		goto exit;
+	}
+
+	if (is_state(inst, MSM_VIDC_OPEN) ||
+	    is_state(inst, MSM_VIDC_INPUT_STREAMING)) {
+		i_vpr_e(inst, "%s: not allowed in state: %s\n", __func__,
+			state_name(inst->state));
+		goto exit;
+	}
+
+	i_vpr_h(inst, "%s: queue pending batch buffers\n", __func__);
+	rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT);
+	if (rc) {
+		i_vpr_e(inst, "%s: batch qbufs failed\n", __func__);
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+
+exit:
+	inst_unlock(inst, __func__);
+	put_inst(inst);
+}
+
+int msm_vidc_flush_buffers(struct msm_vidc_inst *inst,
+			   enum msm_vidc_buffer_type type)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf, *dummy;
+	enum msm_vidc_buffer_type buffer_type[1];
+	int i;
+
+	core = inst->core;
+
+	if (is_input_buffer(type)) {
+		buffer_type[0] = MSM_VIDC_BUF_INPUT;
+	} else if (is_output_buffer(type)) {
+		buffer_type[0] = MSM_VIDC_BUF_OUTPUT;
+	} else {
+		i_vpr_h(inst, "%s: invalid buffer type %d\n",
+			__func__, type);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(buffer_type); i++) {
+		buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__);
+		if (!buffers)
+			return -EINVAL;
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			if (buf->attr & MSM_VIDC_ATTR_QUEUED ||
+			    buf->attr & MSM_VIDC_ATTR_DEFERRED) {
+				print_vidc_buffer(VIDC_HIGH, "high", "flushing buffer", inst, buf);
+				if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) {
+					buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE;
+					buf->data_size = 0;
+					if (buf->dbuf_get) {
+						call_mem_op(core, dma_buf_put, inst, buf->dmabuf);
+						buf->dbuf_get = 0;
+					}
+					msm_vidc_vb2_buffer_done(inst, buf);
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+int msm_vidc_flush_read_only_buffers(struct msm_vidc_inst *inst,
+				     enum msm_vidc_buffer_type type)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *ro_buf, *dummy;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (!is_decode_session(inst) || !is_output_buffer(type))
+		return 0;
+
+	list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+		if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)
+			continue;
+		print_vidc_buffer(VIDC_ERR, "high", "flush ro buf", inst, ro_buf);
+		if (ro_buf->attach && ro_buf->sg_table)
+			call_mem_op(core, dma_buf_unmap_attachment, core,
+				    ro_buf->attach, ro_buf->sg_table);
+		if (ro_buf->attach && ro_buf->dmabuf)
+			call_mem_op(core, dma_buf_detach, core,
+				    ro_buf->dmabuf, ro_buf->attach);
+		if (ro_buf->dbuf_get)
+			call_mem_op(core, dma_buf_put, inst, ro_buf->dmabuf);
+		ro_buf->attach = NULL;
+		ro_buf->sg_table = NULL;
+		ro_buf->dmabuf = NULL;
+		ro_buf->dbuf_get = 0;
+		ro_buf->device_addr = 0x0;
+		list_del_init(&ro_buf->list);
+		msm_vidc_pool_free(inst, ro_buf);
+	}
+
+	return rc;
+}
+
+void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf, *dummy;
+	struct msm_vidc_timestamp *ts, *dummy_ts;
+	struct msm_memory_dmabuf *dbuf, *dummy_dbuf;
+	struct msm_vidc_input_timer *timer, *dummy_timer;
+	struct msm_vidc_buffer_stats *stats, *dummy_stats;
+	struct msm_vidc_inst_cap_entry *entry, *dummy_entry;
+	struct msm_vidc_input_cr_data *cr, *dummy_cr;
+	struct msm_vidc_core *core;
+
+	static const enum msm_vidc_buffer_type ext_buf_types[] = {
+		MSM_VIDC_BUF_INPUT,
+		MSM_VIDC_BUF_OUTPUT,
+	};
+	static const enum msm_vidc_buffer_type internal_buf_types[] = {
+		MSM_VIDC_BUF_BIN,
+		MSM_VIDC_BUF_ARP,
+		MSM_VIDC_BUF_COMV,
+		MSM_VIDC_BUF_NON_COMV,
+		MSM_VIDC_BUF_LINE,
+		MSM_VIDC_BUF_DPB,
+		MSM_VIDC_BUF_PERSIST,
+		MSM_VIDC_BUF_VPSS,
+	};
+	int i;
+
+	core = inst->core;
+
+	for (i = 0; i < ARRAY_SIZE(internal_buf_types); i++) {
+		buffers = msm_vidc_get_buffers(inst, internal_buf_types[i], __func__);
+		if (!buffers)
+			continue;
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			i_vpr_h(inst,
+				"destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n",
+				buf->type, buf->index, buf->fd, buf->device_addr, buf->buffer_size);
+			msm_vidc_destroy_internal_buffer(inst, buf);
+		}
+	}
+
+	/*
+	 * read_only list does not take dma ref_count using dma_buf_get().
+	 * dma_buf ptr will be obselete when its ref_count reaches zero.
+	 * Hence printthe dma_buf info before releasing the ref count.
+	 */
+	list_for_each_entry_safe(buf, dummy, &inst->buffers.read_only.list, list) {
+		print_vidc_buffer(VIDC_ERR, "err ", "destroying ro buf", inst, buf);
+		if (buf->attach && buf->sg_table)
+			call_mem_op(core, dma_buf_unmap_attachment, core,
+				    buf->attach, buf->sg_table);
+		if (buf->attach && buf->dmabuf)
+			call_mem_op(core, dma_buf_detach, core, buf->dmabuf, buf->attach);
+		if (buf->dbuf_get)
+			call_mem_op(core, dma_buf_put, inst, buf->dmabuf);
+		list_del_init(&buf->list);
+		msm_vidc_pool_free(inst, buf);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ext_buf_types); i++) {
+		buffers = msm_vidc_get_buffers(inst, ext_buf_types[i], __func__);
+		if (!buffers)
+			continue;
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			if (buf->dbuf_get || buf->attach || buf->sg_table)
+				print_vidc_buffer(VIDC_ERR, "err ", "destroying: put dmabuf",
+						  inst, buf);
+			if (buf->attach && buf->sg_table)
+				call_mem_op(core, dma_buf_unmap_attachment, core,
+					    buf->attach, buf->sg_table);
+			if (buf->attach && buf->dmabuf)
+				call_mem_op(core, dma_buf_detach, core, buf->dmabuf, buf->attach);
+			if (buf->dbuf_get)
+				call_mem_op(core, dma_buf_put, inst, buf->dmabuf);
+			list_del_init(&buf->list);
+			msm_vidc_pool_free(inst, buf);
+		}
+	}
+
+	list_for_each_entry_safe(ts, dummy_ts, &inst->timestamps.list, sort.list) {
+		i_vpr_e(inst, "%s: removing ts: val %lld, rank %lld\n",
+			__func__, ts->sort.val, ts->rank);
+		list_del(&ts->sort.list);
+		msm_vidc_pool_free(inst, ts);
+	}
+
+	list_for_each_entry_safe(timer, dummy_timer, &inst->input_timer_list, list) {
+		i_vpr_e(inst, "%s: removing input_timer %lld\n",
+			__func__, timer->time_us);
+		list_del(&timer->list);
+		msm_vidc_pool_free(inst, timer);
+	}
+
+	list_for_each_entry_safe(stats, dummy_stats, &inst->buffer_stats_list, list) {
+		list_del(&stats->list);
+		msm_vidc_pool_free(inst, stats);
+	}
+
+	list_for_each_entry_safe(dbuf, dummy_dbuf, &inst->dmabuf_tracker, list) {
+		struct dma_buf *dmabuf;
+		struct inode *f_inode;
+		unsigned long inode_num = 0;
+
+		dmabuf = dbuf->dmabuf;
+		if (dmabuf && dmabuf->file) {
+			f_inode = file_inode(dmabuf->file);
+			if (f_inode)
+				inode_num = f_inode->i_ino;
+		}
+		i_vpr_e(inst, "%s: removing dma_buf %p, inode %lu, refcount %u\n",
+			__func__, dbuf->dmabuf, inode_num, dbuf->refcount);
+		call_mem_op(core, dma_buf_put_completely, inst, dbuf);
+	}
+
+	list_for_each_entry_safe(entry, dummy_entry, &inst->firmware_list, list) {
+		i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del(&entry->list);
+		vfree(entry);
+	}
+
+	list_for_each_entry_safe(entry, dummy_entry, &inst->children_list, list) {
+		i_vpr_e(inst, "%s: child list: %s\n", __func__, cap_name(entry->cap_id));
+		list_del(&entry->list);
+		vfree(entry);
+	}
+
+	list_for_each_entry_safe(entry, dummy_entry, &inst->caps_list, list) {
+		list_del(&entry->list);
+		vfree(entry);
+	}
+
+	list_for_each_entry_safe(cr, dummy_cr, &inst->enc_input_crs, list) {
+		list_del(&cr->list);
+		vfree(cr);
+	}
+
+	/* destroy buffers from pool */
+	msm_vidc_pools_deinit(inst);
+}
+
+static void msm_vidc_close_helper(struct kref *kref)
+{
+	struct msm_vidc_inst *inst = container_of(kref,
+		struct msm_vidc_inst, kref);
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	msm_vidc_debugfs_deinit_inst(inst);
+	if (is_decode_session(inst))
+		msm_vdec_inst_deinit(inst);
+	else if (is_encode_session(inst))
+		msm_venc_inst_deinit(inst);
+	/**
+	 * Lock is not necessay here, but in force close case,
+	 * vb2q_deinit() will attempt to call stop_streaming()
+	 * vb2 callback and i.e expecting inst lock to be taken.
+	 * So acquire lock before calling vb2q_deinit.
+	 */
+	inst_lock(inst, __func__);
+	msm_vidc_vb2_queue_deinit(inst);
+	msm_vidc_v4l2_fh_deinit(inst);
+	inst_unlock(inst, __func__);
+	destroy_workqueue(inst->workq);
+	msm_vidc_destroy_buffers(inst);
+	msm_vidc_remove_session(inst);
+	msm_vidc_remove_dangling_session(inst);
+	mutex_destroy(&inst->client_lock);
+	mutex_destroy(&inst->ctx_q_lock);
+	mutex_destroy(&inst->lock);
+	vfree(inst);
+}
+
+struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core,
+				   struct msm_vidc_inst *instance)
+{
+	struct msm_vidc_inst *inst = NULL;
+	bool matches = false;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst == instance) {
+			matches = true;
+			break;
+		}
+	}
+	inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
+	mutex_unlock(&core->lock);
+	return inst;
+}
+
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+			       u32 session_id)
+{
+	struct msm_vidc_inst *inst = NULL;
+	bool matches = false;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->session_id == session_id) {
+			matches = true;
+			break;
+		}
+	}
+	inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
+	mutex_unlock(&core->lock);
+	return inst;
+}
+
+void put_inst(struct msm_vidc_inst *inst)
+{
+	kref_put(&inst->kref, msm_vidc_close_helper);
+}
+
+void core_lock(struct msm_vidc_core *core, const char *function)
+{
+	mutex_lock(&core->lock);
+}
+
+void core_unlock(struct msm_vidc_core *core, const char *function)
+{
+	mutex_unlock(&core->lock);
+}
+
+void inst_lock(struct msm_vidc_inst *inst, const char *function)
+{
+	mutex_lock(&inst->lock);
+}
+
+void inst_unlock(struct msm_vidc_inst *inst, const char *function)
+{
+	mutex_unlock(&inst->lock);
+}
+
+void client_lock(struct msm_vidc_inst *inst, const char *function)
+{
+	mutex_lock(&inst->client_lock);
+}
+
+void client_unlock(struct msm_vidc_inst *inst, const char *function)
+{
+	mutex_unlock(&inst->client_lock);
+}
+
+int msm_vidc_update_bitstream_buffer_size(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct v4l2_format *fmt;
+
+	core = inst->core;
+
+	if (is_decode_session(inst)) {
+		fmt = &inst->fmts[INPUT_PORT];
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, buffer_size,
+									 inst, MSM_VIDC_BUF_INPUT);
+	}
+
+	return 0;
+}
+
+int msm_vidc_update_buffer_count(struct msm_vidc_inst *inst, u32 port)
+{
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	switch (port) {
+	case INPUT_PORT:
+		inst->buffers.input.min_count = call_session_op(core, min_count,
+								inst, MSM_VIDC_BUF_INPUT);
+		inst->buffers.input.extra_count = call_session_op(core, extra_count,
+								  inst, MSM_VIDC_BUF_INPUT);
+		if (inst->buffers.input.actual_count <
+			inst->buffers.input.min_count +
+			inst->buffers.input.extra_count) {
+			inst->buffers.input.actual_count =
+				inst->buffers.input.min_count +
+				inst->buffers.input.extra_count;
+		}
+
+		i_vpr_h(inst, "%s: type:  INPUT, count: min %u, extra %u, actual %u\n", __func__,
+			inst->buffers.input.min_count,
+			inst->buffers.input.extra_count,
+			inst->buffers.input.actual_count);
+		break;
+	case OUTPUT_PORT:
+		if (!inst->bufq[INPUT_PORT].vb2q->streaming)
+			inst->buffers.output.min_count = call_session_op(core, min_count,
+									 inst, MSM_VIDC_BUF_OUTPUT);
+		inst->buffers.output.extra_count = call_session_op(core, extra_count,
+								   inst, MSM_VIDC_BUF_OUTPUT);
+		if (inst->buffers.output.actual_count <
+			inst->buffers.output.min_count +
+			inst->buffers.output.extra_count) {
+			inst->buffers.output.actual_count =
+				inst->buffers.output.min_count +
+				inst->buffers.output.extra_count;
+		}
+
+		i_vpr_h(inst, "%s: type: OUTPUT, count: min %u, extra %u, actual %u\n", __func__,
+			inst->buffers.output.min_count,
+			inst->buffers.output.extra_count,
+			inst->buffers.output.actual_count);
+		break;
+	default:
+		d_vpr_e("%s unknown port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void msm_vidc_schedule_core_deinit(struct msm_vidc_core *core)
+{
+	if (!core->capabilities[FW_UNLOAD].value)
+		return;
+
+	cancel_delayed_work(&core->fw_unload_work);
+
+	schedule_delayed_work(&core->fw_unload_work,
+			      msecs_to_jiffies(core->capabilities[FW_UNLOAD_DELAY].value));
+
+	d_vpr_h("firmware unload delayed by %u ms\n",
+		core->capabilities[FW_UNLOAD_DELAY].value);
+}
+
+static const char *get_codec_str(enum msm_vidc_codec_type type)
+{
+	switch (type) {
+	case MSM_VIDC_H264: return " avc";
+	case MSM_VIDC_HEVC: return "hevc";
+	case MSM_VIDC_VP9:  return " vp9";
+	}
+
+	return "....";
+}
+
+static const char *get_domain_str(enum msm_vidc_domain_type type)
+{
+	switch (type) {
+	case MSM_VIDC_ENCODER: return "E";
+	case MSM_VIDC_DECODER: return "D";
+	}
+
+	return ".";
+}
+
+int msm_vidc_update_debug_str(struct msm_vidc_inst *inst)
+{
+	u32 sid;
+	const char *codec;
+	const char *domain;
+
+	sid = inst->session_id;
+	codec = get_codec_str(inst->codec);
+	domain = get_domain_str(inst->domain);
+
+	snprintf(inst->debug_str, sizeof(inst->debug_str), "%08x: %s%s",
+		 sid, codec, domain);
+
+	d_vpr_h("%s: sid: %08x, codec: %s, domain: %s, final: %s\n",
+		__func__, sid, codec, domain, inst->debug_str);
+
+	return 0;
+}
+
+static int msm_vidc_print_running_instances_info(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *inst;
+	u32 height, width, fps, orate;
+	struct msm_vidc_inst_cap *cap;
+	struct v4l2_format *out_f;
+	struct v4l2_format *inp_f;
+	char prop[64];
+
+	d_vpr_e("Print all running instances\n");
+	d_vpr_e("%6s | %6s | %5s | %5s | %5s\n", "width", "height", "fps", "orate", "prop");
+
+	core_lock(core, __func__);
+	list_for_each_entry(inst, &core->instances, list) {
+		out_f = &inst->fmts[OUTPUT_PORT];
+		inp_f = &inst->fmts[INPUT_PORT];
+		cap = &inst->capabilities[0];
+		memset(&prop, 0, sizeof(prop));
+
+		width = max(out_f->fmt.pix_mp.width, inp_f->fmt.pix_mp.width);
+		height = max(out_f->fmt.pix_mp.height, inp_f->fmt.pix_mp.height);
+		fps = cap[FRAME_RATE].value >> 16;
+		orate = cap[OPERATING_RATE].value >> 16;
+
+		strlcat(prop, "RT ", sizeof(prop));
+
+		i_vpr_e(inst, "%6u | %6u | %5u | %5u | %5s\n", width, height, fps, orate, prop);
+	}
+	core_unlock(core, __func__);
+
+	return 0;
+}
+
+int msm_vidc_get_inst_load(struct msm_vidc_inst *inst)
+{
+	u32 mbpf, fps;
+	u32 frame_rate, operating_rate, input_rate, timestamp_rate;
+
+	mbpf = msm_vidc_get_mbs_per_frame(inst);
+	frame_rate = msm_vidc_get_frame_rate(inst);
+	operating_rate = msm_vidc_get_operating_rate(inst);
+	fps = max(frame_rate, operating_rate);
+
+	if (is_decode_session(inst)) {
+		input_rate = msm_vidc_get_input_rate(inst);
+		timestamp_rate = msm_vidc_get_timestamp_rate(inst);
+		fps = max(fps, input_rate);
+		fps = max(fps, timestamp_rate);
+	}
+
+	return mbpf * fps;
+}
+
+int msm_vidc_check_core_mbps(struct msm_vidc_inst *inst)
+{
+	u32 mbps = 0, total_mbps = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *instance;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry(instance, &core->instances, list) {
+		/* ignore invalid/error session */
+		if (is_session_error(instance))
+			continue;
+
+		mbps = msm_vidc_get_inst_load(instance);
+		total_mbps += mbps;
+	}
+	core_unlock(core, __func__);
+
+	/* reject if cumulative mbps of all sessions is greater than MAX_MBPS */
+	if (total_mbps > core->capabilities[MAX_MBPS].value) {
+		i_vpr_e(inst, "%s: Hardware overloaded. needed %u, max %u", __func__,
+			total_mbps, core->capabilities[MAX_MBPS].value);
+		return -ENOMEM;
+	}
+
+	i_vpr_h(inst, "%s: HW load needed %u is within max %u", __func__,
+		total_mbps, core->capabilities[MAX_MBPS].value);
+
+	return 0;
+}
+
+int msm_vidc_check_core_mbpf(struct msm_vidc_inst *inst)
+{
+	u32 video_mbpf = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *instance;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry(instance, &core->instances, list) {
+		video_mbpf += msm_vidc_get_mbs_per_frame(instance);
+	}
+	core_unlock(core, __func__);
+
+	if (video_mbpf > core->capabilities[MAX_MBPF].value) {
+		i_vpr_e(inst, "%s: video overloaded. needed %u, max %u", __func__,
+			video_mbpf, core->capabilities[MAX_MBPF].value);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int msm_vidc_check_inst_mbpf(struct msm_vidc_inst *inst)
+{
+	u32 mbpf = 0, max_mbpf = 0;
+	struct msm_vidc_inst_cap *cap;
+
+	cap = &inst->capabilities[0];
+
+	if (is_encode_session(inst) && cap[LOSSLESS].value)
+		max_mbpf = cap[LOSSLESS_MBPF].max;
+	else
+		max_mbpf = cap[MBPF].max;
+
+	/* check current session mbpf */
+	mbpf = msm_vidc_get_mbs_per_frame(inst);
+	if (mbpf > max_mbpf) {
+		i_vpr_e(inst, "%s: session overloaded. needed %u, max %u", __func__,
+			mbpf, max_mbpf);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+u32 msm_vidc_get_max_bitrate(struct msm_vidc_inst *inst)
+{
+	u32 max_bitrate = 0x7fffffff;
+
+	if (inst->capabilities[ALL_INTRA].value)
+		max_bitrate = min(max_bitrate,
+				  (u32)inst->capabilities[ALLINTRA_MAX_BITRATE].max);
+
+	if (inst->codec == MSM_VIDC_HEVC) {
+		max_bitrate = min_t(u32, max_bitrate,
+				    inst->capabilities[CABAC_MAX_BITRATE].max);
+	} else if (inst->codec == MSM_VIDC_H264) {
+		if (inst->capabilities[ENTROPY_MODE].value ==
+			V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC)
+			max_bitrate = min(max_bitrate,
+					  (u32)inst->capabilities[CAVLC_MAX_BITRATE].max);
+		else
+			max_bitrate = min(max_bitrate,
+					  (u32)inst->capabilities[CABAC_MAX_BITRATE].max);
+	}
+	if (max_bitrate == 0x7fffffff || !max_bitrate)
+		max_bitrate = min(max_bitrate, (u32)inst->capabilities[BIT_RATE].max);
+
+	return max_bitrate;
+}
+
+static int msm_vidc_check_resolution_supported(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_inst_cap *cap;
+	u32 width = 0, height = 0, min_width, min_height,
+		max_width, max_height;
+	bool is_interlaced = false;
+
+	cap = &inst->capabilities[0];
+
+	if (is_decode_session(inst)) {
+		width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
+		height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+	} else if (is_encode_session(inst)) {
+		width = inst->crop.width;
+		height = inst->crop.height;
+	}
+
+	if (is_encode_session(inst) && cap[LOSSLESS].value) {
+		min_width = cap[LOSSLESS_FRAME_WIDTH].min;
+		max_width = cap[LOSSLESS_FRAME_WIDTH].max;
+		min_height = cap[LOSSLESS_FRAME_HEIGHT].min;
+		max_height = cap[LOSSLESS_FRAME_HEIGHT].max;
+	} else {
+		min_width = cap[FRAME_WIDTH].min;
+		max_width = cap[FRAME_WIDTH].max;
+		min_height = cap[FRAME_HEIGHT].min;
+		max_height = cap[FRAME_HEIGHT].max;
+	}
+
+	/* check if input width and height is in supported range */
+	if (is_decode_session(inst) || is_encode_session(inst)) {
+		if (!in_range(width, min_width, max_width) ||
+		    !in_range(height, min_height, max_height)) {
+			i_vpr_e(inst,
+				"%s: unsupported input wxh [%u x %u], allowed range: [%u x %u] to [%u x %u]\n",
+				__func__, width, height, min_width,
+				min_height, max_width, max_height);
+			return -EINVAL;
+		}
+	}
+
+	/* check interlace supported resolution */
+	is_interlaced = cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE;
+	if (is_interlaced && (width > INTERLACE_WIDTH_MAX || height > INTERLACE_HEIGHT_MAX ||
+			      NUM_MBS_PER_FRAME(width, height) > INTERLACE_MB_PER_FRAME_MAX)) {
+		i_vpr_e(inst, "%s: unsupported interlace wxh [%u x %u], max [%u x %u]\n",
+			__func__, width, height, INTERLACE_WIDTH_MAX, INTERLACE_HEIGHT_MAX);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_vidc_check_max_sessions(struct msm_vidc_inst *inst)
+{
+	u32 width = 0, height = 0;
+	u32 num_1080p_sessions = 0, num_4k_sessions = 0, num_8k_sessions = 0;
+	struct msm_vidc_inst *i;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	list_for_each_entry(i, &core->instances, list) {
+		if (is_decode_session(i)) {
+			width = i->fmts[INPUT_PORT].fmt.pix_mp.width;
+			height = i->fmts[INPUT_PORT].fmt.pix_mp.height;
+		} else if (is_encode_session(i)) {
+			width = i->crop.width;
+			height = i->crop.height;
+		}
+
+		/*
+		 * one 8k session equals to 64 720p sessions in reality.
+		 * So for one 8k session the number of 720p sessions will
+		 * exceed max supported session count(16), hence one 8k session
+		 * will be rejected as well.
+		 * Therefore, treat one 8k session equal to two 4k sessions and
+		 * one 4k session equal to two 1080p sessions and
+		 * one 1080p session equal to two 720p sessions. This equation
+		 * will make one 8k session equal to eight 720p sessions
+		 * which looks good.
+		 *
+		 * Do not treat resolutions above 4k as 8k session instead
+		 * treat (4K + half 4k) above as 8k session
+		 */
+		if (res_is_greater_than(width, height, 4096 + (4096 >> 1), 2176 + (2176 >> 1))) {
+			num_8k_sessions += 1;
+			num_4k_sessions += 2;
+			num_1080p_sessions += 4;
+		} else if (res_is_greater_than(width, height, 1920 + (1920 >> 1),
+					       1088 + (1088 >> 1))) {
+			num_4k_sessions += 1;
+			num_1080p_sessions += 2;
+		} else if (res_is_greater_than(width, height, 1280 + (1280 >> 1),
+					       736 + (736 >> 1))) {
+			num_1080p_sessions += 1;
+		}
+	}
+	core_unlock(core, __func__);
+
+	if (num_8k_sessions > core->capabilities[MAX_NUM_8K_SESSIONS].value) {
+		i_vpr_e(inst, "%s: total 8k sessions %d, exceeded max limit %d\n",
+			__func__, num_8k_sessions,
+			core->capabilities[MAX_NUM_8K_SESSIONS].value);
+		return -ENOMEM;
+	}
+
+	if (num_4k_sessions > core->capabilities[MAX_NUM_4K_SESSIONS].value) {
+		i_vpr_e(inst, "%s: total 4K sessions %d, exceeded max limit %d\n",
+			__func__, num_4k_sessions,
+			core->capabilities[MAX_NUM_4K_SESSIONS].value);
+		return -ENOMEM;
+	}
+
+	if (num_1080p_sessions > core->capabilities[MAX_NUM_1080P_SESSIONS].value) {
+		i_vpr_e(inst, "%s: total 1080p sessions %d, exceeded max limit %d\n",
+			__func__, num_1080p_sessions,
+			core->capabilities[MAX_NUM_1080P_SESSIONS].value);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_vidc_check_core_mbps(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_check_core_mbpf(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_check_inst_mbpf(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_check_resolution_supported(inst);
+	if (rc)
+		goto exit;
+
+	rc = msm_vidc_check_max_sessions(inst);
+	if (rc)
+		goto exit;
+
+exit:
+	if (rc) {
+		i_vpr_e(inst, "%s: current session not supported\n", __func__);
+		msm_vidc_print_running_instances_info(inst->core);
+	}
+
+	return rc;
+}
+
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+	u32 iwidth, owidth, iheight, oheight, ds_factor;
+
+	if (is_decode_session(inst)) {
+		i_vpr_h(inst, "%s: Scaling is supported for encode session only\n", __func__);
+		return 0;
+	}
+
+	if (!is_scaling_enabled(inst)) {
+		i_vpr_h(inst, "%s: Scaling not enabled. skip scaling check\n", __func__);
+		return 0;
+	}
+
+	iwidth = inst->crop.width;
+	iheight = inst->crop.height;
+	owidth = inst->compose.width;
+	oheight = inst->compose.height;
+	ds_factor = inst->capabilities[SCALE_FACTOR].value;
+
+	/* upscaling: encoder doesnot support upscaling */
+	if (owidth > iwidth || oheight > iheight) {
+		i_vpr_e(inst, "%s: upscale not supported: input [%u x %u], output [%u x %u]\n",
+			__func__, iwidth, iheight, owidth, oheight);
+		return -EINVAL;
+	}
+
+	/* downscaling: only supported up to 1/8 of width & 1/8 of height */
+	if (iwidth > owidth * ds_factor || iheight > oheight * ds_factor) {
+		i_vpr_e(inst,
+			"%s: unsupported ratio: input [%u x %u], output [%u x %u], ratio %u\n",
+			__func__, iwidth, iheight, owidth, oheight, ds_factor);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct msm_vidc_fw_query_params {
+	u32 hfi_prop_name;
+	u32 port;
+};
+
+int msm_vidc_get_properties(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int i;
+
+	static const struct msm_vidc_fw_query_params fw_query_params[] = {
+		{HFI_PROP_STAGE, HFI_PORT_NONE},
+		{HFI_PROP_PIPE, HFI_PORT_NONE},
+		{HFI_PROP_QUALITY_MODE, HFI_PORT_BITSTREAM}
+	};
+
+	for (i = 0; i < ARRAY_SIZE(fw_query_params); i++) {
+		if (is_decode_session(inst)) {
+			if (fw_query_params[i].hfi_prop_name == HFI_PROP_QUALITY_MODE)
+				continue;
+		}
+
+		i_vpr_l(inst, "%s: querying fw for property %#x\n", __func__,
+			fw_query_params[i].hfi_prop_name);
+
+		rc = venus_hfi_session_property(inst,
+						fw_query_params[i].hfi_prop_name,
+						(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+						HFI_HOST_FLAGS_INTR_REQUIRED |
+						HFI_HOST_FLAGS_GET_PROPERTY),
+						fw_query_params[i].port,
+						HFI_PAYLOAD_NONE,
+						NULL,
+						0);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+struct context_bank_info *msm_vidc_get_context_bank_for_region(struct msm_vidc_core *core,
+							       enum msm_vidc_buffer_region region)
+{
+	struct context_bank_info *cb = NULL, *match = NULL;
+
+	if (!region || region >= MSM_VIDC_REGION_MAX) {
+		d_vpr_e("Invalid region %#x\n", region);
+		return NULL;
+	}
+
+	venus_hfi_for_each_context_bank(core, cb) {
+		if (cb->region == region) {
+			match = cb;
+			break;
+		}
+	}
+	if (!match)
+		d_vpr_e("cb not found for region %#x\n", region);
+
+	return match;
+}
+
+struct context_bank_info *msm_vidc_get_context_bank_for_device(struct msm_vidc_core *core,
+							       struct device *dev)
+{
+	struct context_bank_info *cb = NULL, *match = NULL;
+
+	venus_hfi_for_each_context_bank(core, cb) {
+		if (of_device_is_compatible(dev->of_node, cb->name)) {
+			match = cb;
+			break;
+		}
+	}
+	if (!match)
+		d_vpr_e("cb not found for dev %s\n", dev_name(dev));
+
+	return match;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (9 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 10/33] iris: vidc: add helper functions Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 16:28   ` Bjorn Andersson
  2023-07-28 13:23 ` [PATCH 12/33] iris: vidc: add helper functions for resource management Vikash Garodia
                   ` (24 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements helper functions for allocating, freeing,
mapping and unmapping memory.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_memory.h  |  83 ++++
 .../platform/qcom/iris/vidc/src/msm_vidc_memory.c  | 448 +++++++++++++++++++++
 2 files changed, 531 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
new file mode 100644
index 0000000..d6d244a
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_MEMORY_H_
+#define _MSM_VIDC_MEMORY_H_
+
+#include "msm_vidc_internal.h"
+
+struct msm_memory_dmabuf {
+	struct list_head       list;
+	struct dma_buf        *dmabuf;
+	u32                    refcount;
+};
+
+enum msm_memory_pool_type {
+	MSM_MEM_POOL_BUFFER  = 0,
+	MSM_MEM_POOL_ALLOC_MAP,
+	MSM_MEM_POOL_TIMESTAMP,
+	MSM_MEM_POOL_DMABUF,
+	MSM_MEM_POOL_BUF_TIMER,
+	MSM_MEM_POOL_BUF_STATS,
+	MSM_MEM_POOL_MAX,
+};
+
+struct msm_memory_alloc_header {
+	struct list_head       list;
+	u32                    type;
+	bool                   busy;
+	void                  *buf;
+};
+
+struct msm_memory_pool {
+	u32                    size;
+	char                  *name;
+	struct list_head       free_pool; /* list of struct msm_memory_alloc_header */
+	struct list_head       busy_pool; /* list of struct msm_memory_alloc_header */
+};
+
+void *msm_vidc_pool_alloc(struct msm_vidc_inst *inst,
+			  enum msm_memory_pool_type type);
+void msm_vidc_pool_free(struct msm_vidc_inst *inst, void *vidc_buf);
+int msm_vidc_pools_init(struct msm_vidc_inst *inst);
+void msm_vidc_pools_deinit(struct msm_vidc_inst *inst);
+
+#define call_mem_op(c, op, ...)                  \
+	(((c) && (c)->mem_ops && (c)->mem_ops->op) ? \
+	((c)->mem_ops->op(__VA_ARGS__)) : 0)
+
+struct msm_vidc_memory_ops {
+	struct dma_buf *(*dma_buf_get)(struct msm_vidc_inst *inst,
+				       int fd);
+	void (*dma_buf_put)(struct msm_vidc_inst *inst,
+			    struct dma_buf *dmabuf);
+	void (*dma_buf_put_completely)(struct msm_vidc_inst *inst,
+				       struct msm_memory_dmabuf *buf);
+	struct dma_buf_attachment *(*dma_buf_attach)(struct msm_vidc_core *core,
+						     struct dma_buf *dbuf,
+						     struct device *dev);
+	int (*dma_buf_detach)(struct msm_vidc_core *core, struct dma_buf *dbuf,
+			      struct dma_buf_attachment *attach);
+	struct sg_table *(*dma_buf_map_attachment)(struct msm_vidc_core *core,
+						   struct dma_buf_attachment *attach);
+	int (*dma_buf_unmap_attachment)(struct msm_vidc_core *core,
+					struct dma_buf_attachment *attach,
+					struct sg_table *table);
+	int (*memory_alloc_map)(struct msm_vidc_core *core,
+				struct msm_vidc_mem *mem);
+	int (*memory_unmap_free)(struct msm_vidc_core *core,
+				 struct msm_vidc_mem *mem);
+	int (*mem_dma_map_page)(struct msm_vidc_core *core,
+				struct msm_vidc_mem *mem);
+	int (*mem_dma_unmap_page)(struct msm_vidc_core *core,
+				  struct msm_vidc_mem *mem);
+	u32 (*buffer_region)(struct msm_vidc_inst *inst,
+			     enum msm_vidc_buffer_type buffer_type);
+};
+
+const struct msm_vidc_memory_ops *get_mem_ops(void);
+
+#endif // _MSM_VIDC_MEMORY_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
new file mode 100644
index 0000000..c97d9c7
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/dma-heap.h>
+#include <linux/dma-mapping.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "venus_hfi.h"
+
+MODULE_IMPORT_NS(DMA_BUF);
+
+struct msm_vidc_type_size_name {
+	enum msm_memory_pool_type type;
+	u32                       size;
+	char                     *name;
+};
+
+static const struct msm_vidc_type_size_name buftype_size_name_arr[] = {
+	{MSM_MEM_POOL_BUFFER,     sizeof(struct msm_vidc_buffer),     "MSM_MEM_POOL_BUFFER"     },
+	{MSM_MEM_POOL_ALLOC_MAP,  sizeof(struct msm_vidc_mem),        "MSM_MEM_POOL_ALLOC_MAP"  },
+	{MSM_MEM_POOL_TIMESTAMP,  sizeof(struct msm_vidc_timestamp),  "MSM_MEM_POOL_TIMESTAMP"  },
+	{MSM_MEM_POOL_DMABUF,     sizeof(struct msm_memory_dmabuf),   "MSM_MEM_POOL_DMABUF"     },
+	{MSM_MEM_POOL_BUF_TIMER,  sizeof(struct msm_vidc_input_timer), "MSM_MEM_POOL_BUF_TIMER" },
+	{MSM_MEM_POOL_BUF_STATS,  sizeof(struct msm_vidc_buffer_stats), "MSM_MEM_POOL_BUF_STATS"},
+};
+
+void *msm_vidc_pool_alloc(struct msm_vidc_inst *inst, enum msm_memory_pool_type type)
+{
+	struct msm_memory_alloc_header *hdr = NULL;
+	struct msm_memory_pool *pool;
+
+	if (type < 0 || type >= MSM_MEM_POOL_MAX) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return NULL;
+	}
+	pool = &inst->pool[type];
+
+	if (!list_empty(&pool->free_pool)) {
+		/* get 1st node from free pool */
+		hdr = list_first_entry(&pool->free_pool, struct msm_memory_alloc_header, list);
+
+		/* move node from free pool to busy pool */
+		list_move_tail(&hdr->list, &pool->busy_pool);
+
+		/* reset existing data */
+		memset((char *)hdr->buf, 0, pool->size);
+
+		/* set busy flag to true. This is to catch double free request */
+		hdr->busy = true;
+
+		return hdr->buf;
+	}
+
+	hdr = vzalloc(pool->size + sizeof(struct msm_memory_alloc_header));
+
+	INIT_LIST_HEAD(&hdr->list);
+	hdr->type = type;
+	hdr->busy = true;
+	hdr->buf = (void *)(hdr + 1);
+	list_add_tail(&hdr->list, &pool->busy_pool);
+
+	return hdr->buf;
+}
+
+void msm_vidc_pool_free(struct msm_vidc_inst *inst, void *vidc_buf)
+{
+	struct msm_memory_alloc_header *hdr;
+	struct msm_memory_pool *pool;
+
+	if (!vidc_buf) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return;
+	}
+	hdr = (struct msm_memory_alloc_header *)vidc_buf - 1;
+
+	/* sanitize buffer addr */
+	if (hdr->buf != vidc_buf) {
+		i_vpr_e(inst, "%s: invalid buf addr %p\n", __func__, vidc_buf);
+		return;
+	}
+
+	/* sanitize pool type */
+	if (hdr->type < 0 || hdr->type >= MSM_MEM_POOL_MAX) {
+		i_vpr_e(inst, "%s: invalid pool type %#x\n", __func__, hdr->type);
+		return;
+	}
+	pool = &inst->pool[hdr->type];
+
+	/* catch double-free request */
+	if (!hdr->busy) {
+		i_vpr_e(inst, "%s: double free request. type %s, addr %p\n", __func__,
+			pool->name, vidc_buf);
+		return;
+	}
+	hdr->busy = false;
+
+	/* move node from busy pool to free pool */
+	list_move_tail(&hdr->list, &pool->free_pool);
+}
+
+static void msm_vidc_destroy_pool_buffers(struct msm_vidc_inst *inst,
+					  enum msm_memory_pool_type type)
+{
+	struct msm_memory_alloc_header *hdr, *dummy;
+	struct msm_memory_pool *pool;
+	u32 fcount = 0, bcount = 0;
+
+	if (type < 0 || type >= MSM_MEM_POOL_MAX) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return;
+	}
+	pool = &inst->pool[type];
+
+	/* detect memleak: busy pool is expected to be empty here */
+	if (!list_empty(&pool->busy_pool))
+		i_vpr_e(inst, "%s: destroy request on active buffer. type %s\n",
+			__func__, pool->name);
+
+	/* destroy all free buffers */
+	list_for_each_entry_safe(hdr, dummy, &pool->free_pool, list) {
+		list_del(&hdr->list);
+		vfree(hdr);
+		fcount++;
+	}
+
+	/* destroy all busy buffers */
+	list_for_each_entry_safe(hdr, dummy, &pool->busy_pool, list) {
+		list_del(&hdr->list);
+		vfree(hdr);
+		bcount++;
+	}
+
+	i_vpr_h(inst, "%s: type: %23s, count: free %2u, busy %2u\n",
+		__func__, pool->name, fcount, bcount);
+}
+
+int msm_vidc_pools_init(struct msm_vidc_inst *inst)
+{
+	u32 i;
+
+	if (ARRAY_SIZE(buftype_size_name_arr) != MSM_MEM_POOL_MAX) {
+		i_vpr_e(inst, "%s: num elements mismatch %lu %u\n", __func__,
+			ARRAY_SIZE(buftype_size_name_arr), MSM_MEM_POOL_MAX);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MSM_MEM_POOL_MAX; i++) {
+		if (i != buftype_size_name_arr[i].type) {
+			i_vpr_e(inst, "%s: type mismatch %u %u\n", __func__,
+				i, buftype_size_name_arr[i].type);
+			return -EINVAL;
+		}
+		inst->pool[i].size = buftype_size_name_arr[i].size;
+		inst->pool[i].name = buftype_size_name_arr[i].name;
+		INIT_LIST_HEAD(&inst->pool[i].free_pool);
+		INIT_LIST_HEAD(&inst->pool[i].busy_pool);
+	}
+
+	return 0;
+}
+
+void msm_vidc_pools_deinit(struct msm_vidc_inst *inst)
+{
+	u32 i = 0;
+
+	/* destroy all buffers from all pool types */
+	for (i = 0; i < MSM_MEM_POOL_MAX; i++)
+		msm_vidc_destroy_pool_buffers(inst, i);
+}
+
+static struct dma_buf *msm_vidc_dma_buf_get(struct msm_vidc_inst *inst, int fd)
+{
+	struct msm_memory_dmabuf *buf = NULL;
+	struct dma_buf *dmabuf = NULL;
+	bool found = false;
+
+	/* get local dmabuf ref for tracking */
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL(dmabuf)) {
+		d_vpr_e("Failed to get dmabuf for %d, error %d\n",
+			fd, PTR_ERR_OR_ZERO(dmabuf));
+		return NULL;
+	}
+
+	/* track dmabuf - inc refcount if already present */
+	list_for_each_entry(buf, &inst->dmabuf_tracker, list) {
+		if (buf->dmabuf == dmabuf) {
+			buf->refcount++;
+			found = true;
+			break;
+		}
+	}
+	if (found) {
+		/* put local dmabuf ref */
+		dma_buf_put(dmabuf);
+		return dmabuf;
+	}
+
+	/* get tracker instance from pool */
+	buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_DMABUF);
+	if (!buf) {
+		i_vpr_e(inst, "%s: dmabuf alloc failed\n", __func__);
+		dma_buf_put(dmabuf);
+		return NULL;
+	}
+	/* hold dmabuf strong ref in tracker */
+	buf->dmabuf = dmabuf;
+	buf->refcount = 1;
+	INIT_LIST_HEAD(&buf->list);
+
+	/* add new dmabuf entry to tracker */
+	list_add_tail(&buf->list, &inst->dmabuf_tracker);
+
+	return dmabuf;
+}
+
+static void msm_vidc_dma_buf_put(struct msm_vidc_inst *inst, struct dma_buf *dmabuf)
+{
+	struct msm_memory_dmabuf *buf = NULL;
+	bool found = false;
+
+	if (!dmabuf) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	/* track dmabuf - dec refcount if already present */
+	list_for_each_entry(buf, &inst->dmabuf_tracker, list) {
+		if (buf->dmabuf == dmabuf) {
+			buf->refcount--;
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		i_vpr_e(inst, "%s: invalid dmabuf %p\n", __func__, dmabuf);
+		return;
+	}
+
+	/* non-zero refcount - do nothing */
+	if (buf->refcount)
+		return;
+
+	/* remove dmabuf entry from tracker */
+	list_del(&buf->list);
+
+	/* release dmabuf strong ref from tracker */
+	dma_buf_put(buf->dmabuf);
+
+	/* put tracker instance back to pool */
+	msm_vidc_pool_free(inst, buf);
+}
+
+static void msm_vidc_dma_buf_put_completely(struct msm_vidc_inst *inst,
+					    struct msm_memory_dmabuf *buf)
+{
+	if (!buf) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	while (buf->refcount) {
+		buf->refcount--;
+		if (!buf->refcount) {
+			/* remove dmabuf entry from tracker */
+			list_del(&buf->list);
+
+			/* release dmabuf strong ref from tracker */
+			dma_buf_put(buf->dmabuf);
+
+			/* put tracker instance back to pool */
+			msm_vidc_pool_free(inst, buf);
+			break;
+		}
+	}
+}
+
+static struct dma_buf_attachment *msm_vidc_dma_buf_attach(struct msm_vidc_core *core,
+							  struct dma_buf *dbuf,
+							  struct device *dev)
+{
+	int rc = 0;
+	struct dma_buf_attachment *attach = NULL;
+
+	if (!dbuf || !dev) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return NULL;
+	}
+
+	attach = dma_buf_attach(dbuf, dev);
+	if (IS_ERR_OR_NULL(attach)) {
+		rc = PTR_ERR_OR_ZERO(attach) ? PTR_ERR_OR_ZERO(attach) : -1;
+		d_vpr_e("Failed to attach dmabuf, error %d\n", rc);
+		return NULL;
+	}
+
+	return attach;
+}
+
+static int msm_vidc_dma_buf_detach(struct msm_vidc_core *core, struct dma_buf *dbuf,
+				   struct dma_buf_attachment *attach)
+{
+	int rc = 0;
+
+	if (!dbuf || !attach) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	dma_buf_detach(dbuf, attach);
+
+	return rc;
+}
+
+static int msm_vidc_dma_buf_unmap_attachment(struct msm_vidc_core *core,
+					     struct dma_buf_attachment *attach,
+					     struct sg_table *table)
+{
+	int rc = 0;
+
+	if (!attach || !table) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
+
+	return rc;
+}
+
+static struct sg_table *msm_vidc_dma_buf_map_attachment(struct msm_vidc_core *core,
+							struct dma_buf_attachment *attach)
+{
+	int rc = 0;
+	struct sg_table *table = NULL;
+
+	if (!attach) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return NULL;
+	}
+
+	table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+	if (IS_ERR_OR_NULL(table)) {
+		rc = PTR_ERR_OR_ZERO(table) ? PTR_ERR_OR_ZERO(table) : -1;
+		d_vpr_e("Failed to map table, error %d\n", rc);
+		return NULL;
+	}
+	if (!table->sgl) {
+		d_vpr_e("%s: sgl is NULL\n", __func__);
+		msm_vidc_dma_buf_unmap_attachment(core, attach, table);
+		return NULL;
+	}
+
+	return table;
+}
+
+static int msm_vidc_memory_alloc_map(struct msm_vidc_core *core, struct msm_vidc_mem *mem)
+{
+	int size = 0;
+	struct context_bank_info *cb = NULL;
+
+	if (!mem) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	size = ALIGN(mem->size, SZ_4K);
+	mem->attrs = DMA_ATTR_WRITE_COMBINE;
+
+	cb = msm_vidc_get_context_bank_for_region(core, mem->region);
+	if (!cb) {
+		d_vpr_e("%s: failed to get context bank device\n", __func__);
+		return -EIO;
+	}
+
+	mem->kvaddr = dma_alloc_attrs(cb->dev, size, &mem->device_addr, GFP_KERNEL,
+				      mem->attrs);
+	if (!mem->kvaddr) {
+		d_vpr_e("%s: dma_alloc_attrs returned NULL\n", __func__);
+		return -ENOMEM;
+	}
+
+	d_vpr_h("%s: dmabuf %pK, size %d, buffer_type %s, secure %d, region %d\n",
+		__func__, mem->kvaddr, mem->size, buf_name(mem->type),
+		mem->secure, mem->region);
+
+	return 0;
+}
+
+static int msm_vidc_memory_unmap_free(struct msm_vidc_core *core, struct msm_vidc_mem *mem)
+{
+	int rc = 0;
+	struct context_bank_info *cb = NULL;
+
+	if (!mem || !mem->device_addr || !mem->kvaddr) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	d_vpr_h("%s: dmabuf %pK, size %d, kvaddr %pK, buffer_type %s, secure %d, region %d\n",
+		__func__, (void *)mem->device_addr, mem->size, mem->kvaddr,
+		buf_name(mem->type), mem->secure, mem->region);
+
+	cb = msm_vidc_get_context_bank_for_region(core, mem->region);
+	if (!cb) {
+		d_vpr_e("%s: failed to get context bank device\n", __func__);
+		return -EIO;
+	}
+
+	dma_free_attrs(cb->dev, mem->size, mem->kvaddr, mem->device_addr, mem->attrs);
+
+	mem->kvaddr = NULL;
+	mem->device_addr = 0;
+
+	return rc;
+}
+
+static u32 msm_vidc_buffer_region(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buffer_type)
+{
+	return MSM_VIDC_NON_SECURE;
+}
+
+static const struct msm_vidc_memory_ops msm_mem_ops = {
+	.dma_buf_get                    = msm_vidc_dma_buf_get,
+	.dma_buf_put                    = msm_vidc_dma_buf_put,
+	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
+	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
+	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
+	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
+	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
+	.memory_alloc_map               = msm_vidc_memory_alloc_map,
+	.memory_unmap_free              = msm_vidc_memory_unmap_free,
+	.buffer_region                  = msm_vidc_buffer_region,
+};
+
+const struct msm_vidc_memory_ops *get_mem_ops(void)
+{
+	return &msm_mem_ops;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 12/33] iris: vidc: add helper functions for resource management
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (10 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 11/33] iris: vidc: add helpers for memory management Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:30   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 13/33] iris: vidc: add helper functions for power management Vikash Garodia
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements ops to initialize, enable and disable extrenal
resources needed by video driver like power domains, clocks etc.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/resources.h  |  259 ++++
 .../media/platform/qcom/iris/vidc/src/resources.c  | 1321 ++++++++++++++++++++
 2 files changed, 1580 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/resources.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/resources.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/resources.h b/drivers/media/platform/qcom/iris/vidc/inc/resources.h
new file mode 100644
index 0000000..9b2588e
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/resources.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_RESOURCES_H_
+#define _MSM_VIDC_RESOURCES_H_
+
+struct icc_path;
+struct regulator;
+struct clk;
+struct reset_control;
+struct llcc_slice_desc;
+struct iommu_domain;
+struct device;
+struct msm_vidc_core;
+
+/*
+ * These are helper macros to iterate over various lists within
+ * msm_vidc_core->resource. 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)->resource->__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 unnecessary complexity.
+ */
+#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \
+	for (__thing = &(__device)->resource->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing < &(__device)->resource->__thingy##_set.__thingy##_tbl[0] + \
+			((__device)->resource->__thingy##_set.count - __from); \
+		++__thing)
+
+#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+		__from) \
+	for (__thing = &(__device)->resource->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing >= &(__device)->resource->__thingy##_set.__thingy##_tbl[0]; \
+		--__thing)
+
+/* Bus set helpers */
+#define venus_hfi_for_each_bus(__device, __binfo) \
+	venus_hfi_for_each_thing(__device, __binfo, bus)
+#define venus_hfi_for_each_bus_reverse(__device, __binfo) \
+	venus_hfi_for_each_thing_reverse(__device, __binfo, bus)
+
+/* 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)
+
+/* Power domain set helpers */
+#define venus_hfi_for_each_power_domain(__device, __pdinfo) \
+	venus_hfi_for_each_thing(__device, __pdinfo, power_domain)
+
+/* 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)
+
+/* Reset clock set helpers */
+#define venus_hfi_for_each_reset_clock(__device, __rcinfo) \
+	venus_hfi_for_each_thing(__device, __rcinfo, reset)
+#define venus_hfi_for_each_reset_clock_reverse(__device, __rcinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __rcinfo, reset)
+#define venus_hfi_for_each_reset_clock_reverse_continue(__device, __rinfo, \
+		__from) \
+	venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
+			reset, __from)
+
+/* Subcache set helpers */
+#define venus_hfi_for_each_subcache(__device, __sinfo) \
+	venus_hfi_for_each_thing(__device, __sinfo, subcache)
+#define venus_hfi_for_each_subcache_reverse(__device, __sinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __sinfo, subcache)
+
+/* Contextbank set helpers */
+#define venus_hfi_for_each_context_bank(__device, __sinfo) \
+	venus_hfi_for_each_thing(__device, __sinfo, context_bank)
+#define venus_hfi_for_each_context_bank_reverse(__device, __sinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __sinfo, context_bank)
+
+enum msm_vidc_branch_mem_flags {
+	MSM_VIDC_CLKFLAG_RETAIN_PERIPH,
+	MSM_VIDC_CLKFLAG_NORETAIN_PERIPH,
+	MSM_VIDC_CLKFLAG_RETAIN_MEM,
+	MSM_VIDC_CLKFLAG_NORETAIN_MEM,
+	MSM_VIDC_CLKFLAG_PERIPH_OFF_SET,
+	MSM_VIDC_CLKFLAG_PERIPH_OFF_CLEAR,
+};
+
+struct bus_info {
+	struct icc_path           *icc;
+	const char                *name;
+	u32                        min_kbps;
+	u32                        max_kbps;
+};
+
+struct bus_set {
+	struct bus_info           *bus_tbl;
+	u32                        count;
+};
+
+struct regulator_info {
+	struct regulator          *regulator;
+	const char                *name;
+	bool                       hw_power_collapse;
+};
+
+struct regulator_set {
+	struct regulator_info     *regulator_tbl;
+	u32                        count;
+};
+
+struct power_domain_info {
+	struct device             *genpd_dev;
+	const char                *name;
+};
+
+struct power_domain_set {
+	struct power_domain_info  *power_domain_tbl;
+	u32                        count;
+};
+
+struct clock_info {
+	struct clk                *clk;
+	const char                *name;
+	u32                        clk_id;
+	bool                       has_scaling;
+	u64                        prev;
+};
+
+struct clock_set {
+	struct clock_info         *clock_tbl;
+	u32                        count;
+};
+
+struct reset_info {
+	struct reset_control      *rst;
+	const char                *name;
+	bool                       exclusive_release;
+};
+
+struct reset_set {
+	struct reset_info         *reset_tbl;
+	u32                        count;
+};
+
+struct subcache_info {
+	struct llcc_slice_desc    *subcache;
+	const char                *name;
+	u32                        llcc_id;
+	bool                       isactive;
+};
+
+struct subcache_set {
+	struct subcache_info      *subcache_tbl;
+	u32                        count;
+	bool                       set_to_fw;
+};
+
+struct addr_range {
+	u32                        start;
+	u32                        size;
+};
+
+struct context_bank_info {
+	const char                *name;
+	struct addr_range          addr_range;
+	bool                       secure;
+	bool                       dma_coherant;
+	struct device             *dev;
+	struct iommu_domain       *domain;
+	u32                        region;
+	u64                        dma_mask;
+};
+
+struct context_bank_set {
+	struct context_bank_info  *context_bank_tbl;
+	u32                        count;
+};
+
+struct frequency_table {
+	unsigned long freq;
+};
+
+struct freq_set {
+	struct frequency_table    *freq_tbl;
+	u32                        count;
+};
+
+struct msm_vidc_resource {
+	u8 __iomem                *register_base_addr;
+	int                        irq;
+	struct bus_set             bus_set;
+	struct regulator_set       regulator_set;
+	struct power_domain_set    power_domain_set;
+	struct clock_set           clock_set;
+	struct reset_set           reset_set;
+	struct subcache_set        subcache_set;
+	struct context_bank_set    context_bank_set;
+	struct freq_set            freq_set;
+	int                        fw_cookie;
+};
+
+#define call_res_op(c, op, ...)                  \
+	(((c) && (c)->res_ops && (c)->res_ops->op) ? \
+	((c)->res_ops->op(__VA_ARGS__)) : 0)
+
+struct msm_vidc_resources_ops {
+	int (*init)(struct msm_vidc_core *core);
+
+	int (*reset_bridge)(struct msm_vidc_core *core);
+	int (*reset_control_acquire)(struct msm_vidc_core *core,
+				     const char *name);
+	int (*reset_control_release)(struct msm_vidc_core *core,
+				     const char *name);
+	int (*reset_control_assert)(struct msm_vidc_core *core,
+				    const char *name);
+	int (*reset_control_deassert)(struct msm_vidc_core *core,
+				      const char *name);
+
+	int (*gdsc_init)(struct msm_vidc_core *core);
+	int (*gdsc_on)(struct msm_vidc_core *core, const char *name);
+	int (*gdsc_off)(struct msm_vidc_core *core, const char *name);
+	int (*gdsc_hw_ctrl)(struct msm_vidc_core *core);
+	int (*gdsc_sw_ctrl)(struct msm_vidc_core *core);
+
+	int (*llcc)(struct msm_vidc_core *core, bool enable);
+	int (*set_bw)(struct msm_vidc_core *core, unsigned long bw_ddr,
+		      unsigned long bw_llcc);
+	int (*set_clks)(struct msm_vidc_core *core, u64 rate);
+
+	int (*clk_disable)(struct msm_vidc_core *core, const char *name);
+	int (*clk_enable)(struct msm_vidc_core *core, const char *name);
+	int (*clk_set_flag)(struct msm_vidc_core *core,
+			    const char *name, enum msm_vidc_branch_mem_flags flag);
+};
+
+const struct msm_vidc_resources_ops *get_resources_ops(void);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/resources.c b/drivers/media/platform/qcom/iris/vidc/src/resources.c
new file mode 100644
index 0000000..b0800b9
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/resources.c
@@ -0,0 +1,1321 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/interconnect.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+#include <linux/sort.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "venus_hfi.h"
+
+/* Less than 50MBps is treated as trivial BW change */
+#define TRIVIAL_BW_THRESHOLD 50000
+#define TRIVIAL_BW_CHANGE(a, b) \
+	((a) > (b) ? (a) - (b) < TRIVIAL_BW_THRESHOLD : \
+		(b) - (a) < TRIVIAL_BW_THRESHOLD)
+
+enum reset_state {
+	INIT = 1,
+	ASSERT,
+	DEASSERT,
+};
+
+/* A comparator to compare loads (needed later on) */
+static inline int cmp(const void *a, const void *b)
+{
+	/* want to sort in reverse so flip the comparison */
+	return ((struct freq_table *)b)->freq -
+		((struct freq_table *)a)->freq;
+}
+
+static void __fatal_error(bool fatal)
+{
+	WARN_ON(fatal);
+}
+
+static void devm_llcc_release(void *res)
+{
+	llcc_slice_putd((struct llcc_slice_desc *)res);
+}
+
+static struct llcc_slice_desc *devm_llcc_get(struct device *dev, u32 id)
+{
+	struct llcc_slice_desc *llcc = NULL;
+	int rc = 0;
+
+	llcc = llcc_slice_getd(id);
+	if (!llcc)
+		return NULL;
+
+	/**
+	 * register release callback with devm, so that when device goes
+	 * out of scope(during remove sequence), devm will take care of
+	 * de-register part by invoking release callback.
+	 */
+	rc = devm_add_action_or_reset(dev, devm_llcc_release, (void *)llcc);
+	if (rc)
+		return NULL;
+
+	return llcc;
+}
+
+static void devm_pd_release(void *res)
+{
+	struct device *pd = (struct device *)res;
+
+	d_vpr_h("%s(): %s\n", __func__, dev_name(pd));
+	dev_pm_domain_detach(pd, true);
+}
+
+static struct device *devm_pd_get(struct device *dev, const char *name)
+{
+	struct device *pd = NULL;
+	int rc = 0;
+
+	pd = dev_pm_domain_attach_by_name(dev, name);
+	if (!pd) {
+		d_vpr_e("%s: pm domain attach failed %s\n", __func__, name);
+		return NULL;
+	}
+
+	rc = devm_add_action_or_reset(dev, devm_pd_release, (void *)pd);
+	if (rc) {
+		d_vpr_e("%s: add action or reset failed %s\n", __func__, name);
+		return NULL;
+	}
+
+	return pd;
+}
+
+static void devm_opp_dl_release(void *res)
+{
+	struct device_link *link = (struct device_link *)res;
+
+	d_vpr_h("%s(): %s\n", __func__, dev_name(&link->link_dev));
+	device_link_del(link);
+}
+
+static int devm_opp_dl_get(struct device *dev, struct device *supplier)
+{
+	u32 flag = DL_FLAG_RPM_ACTIVE | DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS;
+	struct device_link *link = NULL;
+	int rc = 0;
+
+	link = device_link_add(dev, supplier, flag);
+	if (!link) {
+		d_vpr_e("%s: device link add failed\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = devm_add_action_or_reset(dev, devm_opp_dl_release, (void *)link);
+	if (rc) {
+		d_vpr_e("%s: add action or reset failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void devm_pm_runtime_put_sync(void *res)
+{
+	struct device *dev = (struct device *)res;
+
+	d_vpr_h("%s(): %s\n", __func__, dev_name(dev));
+	pm_runtime_put_sync(dev);
+}
+
+static int devm_pm_runtime_get_sync(struct device *dev)
+{
+	int rc = 0;
+
+	rc = pm_runtime_get_sync(dev);
+	if (rc < 0) {
+		d_vpr_e("%s: pm domain get sync failed\n", __func__);
+		return rc;
+	}
+
+	rc = devm_add_action_or_reset(dev, devm_pm_runtime_put_sync, (void *)dev);
+	if (rc) {
+		d_vpr_e("%s: add action or reset failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __opp_set_rate(struct msm_vidc_core *core, u64 freq)
+{
+	unsigned long opp_freq = 0;
+	struct dev_pm_opp *opp;
+	int rc = 0;
+
+	opp_freq = freq;
+
+	/* find max(ceil) freq from opp table */
+	opp = dev_pm_opp_find_freq_ceil(&core->pdev->dev, &opp_freq);
+	if (IS_ERR(opp)) {
+		opp = dev_pm_opp_find_freq_floor(&core->pdev->dev, &opp_freq);
+		if (IS_ERR(opp)) {
+			d_vpr_e("%s: unable to find freq %lld in opp table\n", __func__, freq);
+			return -EINVAL;
+		}
+	}
+	dev_pm_opp_put(opp);
+
+	/* print freq value */
+	d_vpr_h("%s: set rate %lu (requested %llu)\n",
+		__func__, opp_freq, freq);
+
+	/* scale freq to power up mxc & mmcx */
+	rc = dev_pm_opp_set_rate(&core->pdev->dev, opp_freq);
+	if (rc) {
+		d_vpr_e("%s: failed to set rate\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __init_register_base(struct msm_vidc_core *core)
+{
+	struct msm_vidc_resource *res;
+
+	res = core->resource;
+
+	res->register_base_addr = devm_platform_ioremap_resource(core->pdev, 0);
+	if (IS_ERR(res->register_base_addr)) {
+		d_vpr_e("%s: map reg addr failed %ld\n",
+			__func__, PTR_ERR(res->register_base_addr));
+		return -EINVAL;
+	}
+	d_vpr_h("%s: reg_base %p\n", __func__, res->register_base_addr);
+
+	return 0;
+}
+
+static int __init_irq(struct msm_vidc_core *core)
+{
+	struct msm_vidc_resource *res;
+	int rc = 0;
+
+	res = core->resource;
+
+	res->irq = platform_get_irq(core->pdev, 0);
+
+	if (res->irq < 0)
+		d_vpr_e("%s: get irq failed, %d\n", __func__, res->irq);
+
+	d_vpr_h("%s: irq %d\n", __func__, res->irq);
+
+	rc = devm_request_threaded_irq(&core->pdev->dev, res->irq, venus_hfi_isr,
+				       venus_hfi_isr_handler, IRQF_TRIGGER_HIGH, "msm-vidc", core);
+	if (rc) {
+		d_vpr_e("%s: Failed to allocate venus IRQ\n", __func__);
+		return rc;
+	}
+	disable_irq_nosync(res->irq);
+
+	return rc;
+}
+
+static int __init_bus(struct msm_vidc_core *core)
+{
+	const struct bw_table *bus_tbl;
+	struct bus_set *interconnects;
+	struct bus_info *binfo = NULL;
+	u32 bus_count = 0, cnt = 0;
+	int rc = 0;
+
+	interconnects = &core->resource->bus_set;
+
+	bus_tbl = core->platform->data.bw_tbl;
+	bus_count = core->platform->data.bw_tbl_size;
+
+	if (!bus_tbl || !bus_count) {
+		d_vpr_e("%s: invalid bus tbl %p or count %d\n",
+			__func__, bus_tbl, bus_count);
+		return -EINVAL;
+	}
+
+	/* allocate bus_set */
+	interconnects->bus_tbl = devm_kzalloc(&core->pdev->dev,
+					      sizeof(*interconnects->bus_tbl) * bus_count,
+					      GFP_KERNEL);
+	if (!interconnects->bus_tbl) {
+		d_vpr_e("%s: failed to alloc memory for bus table\n", __func__);
+		return -ENOMEM;
+	}
+	interconnects->count = bus_count;
+
+	/* populate bus field from platform data */
+	for (cnt = 0; cnt < interconnects->count; cnt++) {
+		interconnects->bus_tbl[cnt].name = bus_tbl[cnt].name;
+		interconnects->bus_tbl[cnt].min_kbps = bus_tbl[cnt].min_kbps;
+		interconnects->bus_tbl[cnt].max_kbps = bus_tbl[cnt].max_kbps;
+	}
+
+	/* print bus fields */
+	venus_hfi_for_each_bus(core, binfo) {
+		d_vpr_h("%s: name %s min_kbps %u max_kbps %u\n",
+			__func__, binfo->name, binfo->min_kbps, binfo->max_kbps);
+	}
+
+	/* get interconnect handle */
+	venus_hfi_for_each_bus(core, binfo) {
+		binfo->icc = devm_of_icc_get(&core->pdev->dev, binfo->name);
+		if (IS_ERR_OR_NULL(binfo->icc)) {
+			d_vpr_e("%s: failed to get bus: %s\n", __func__, binfo->name);
+			rc = PTR_ERR_OR_ZERO(binfo->icc) ?
+				PTR_ERR_OR_ZERO(binfo->icc) : -EBADHANDLE;
+			binfo->icc = NULL;
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __init_power_domains(struct msm_vidc_core *core)
+{
+	struct power_domain_info *pdinfo = NULL;
+	const struct pd_table *pd_tbl;
+	struct power_domain_set *pds;
+	struct device **opp_vdevs = NULL;
+	const char * const *opp_tbl;
+	u32 pd_count = 0, opp_count = 0, cnt = 0;
+	int rc = 0;
+
+	pds = &core->resource->power_domain_set;
+
+	pd_tbl = core->platform->data.pd_tbl;
+	pd_count = core->platform->data.pd_tbl_size;
+
+	/* skip init if power domain not supported */
+	if (!pd_count) {
+		d_vpr_h("%s: power domain entries not available in db\n", __func__);
+		return 0;
+	}
+
+	/* sanitize power domain table */
+	if (!pd_tbl) {
+		d_vpr_e("%s: invalid power domain tbl\n", __func__);
+		return -EINVAL;
+	}
+
+	/* allocate power_domain_set */
+	pds->power_domain_tbl = devm_kzalloc(&core->pdev->dev,
+					     sizeof(*pds->power_domain_tbl) * pd_count,
+					     GFP_KERNEL);
+	if (!pds->power_domain_tbl) {
+		d_vpr_e("%s: failed to alloc memory for pd table\n", __func__);
+		return -ENOMEM;
+	}
+	pds->count = pd_count;
+
+	/* populate power domain fields */
+	for (cnt = 0; cnt < pds->count; cnt++)
+		pds->power_domain_tbl[cnt].name = pd_tbl[cnt].name;
+
+	/* print power domain fields */
+	venus_hfi_for_each_power_domain(core, pdinfo)
+		d_vpr_h("%s: pd name %s\n", __func__, pdinfo->name);
+
+	/* get power domain handle */
+	venus_hfi_for_each_power_domain(core, pdinfo) {
+		pdinfo->genpd_dev = devm_pd_get(&core->pdev->dev, pdinfo->name);
+		if (IS_ERR_OR_NULL(pdinfo->genpd_dev)) {
+			rc = PTR_ERR_OR_ZERO(pdinfo->genpd_dev) ?
+				PTR_ERR_OR_ZERO(pdinfo->genpd_dev) : -EBADHANDLE;
+			d_vpr_e("%s: failed to get pd: %s\n", __func__, pdinfo->name);
+			pdinfo->genpd_dev = NULL;
+			return rc;
+		}
+	}
+
+	opp_tbl = core->platform->data.opp_tbl;
+	opp_count = core->platform->data.opp_tbl_size;
+
+	/* skip init if opp not supported */
+	if (opp_count < 2) {
+		d_vpr_h("%s: opp entries not available\n", __func__);
+		return 0;
+	}
+
+	/* sanitize opp table */
+	if (!opp_tbl) {
+		d_vpr_e("%s: invalid opp table\n", __func__);
+		return -EINVAL;
+	}
+
+	/* ignore NULL entry at the end of table */
+	opp_count -= 1;
+
+	/* print opp table entries */
+	for (cnt = 0; cnt < opp_count; cnt++)
+		d_vpr_h("%s: opp name %s\n", __func__, opp_tbl[cnt]);
+
+	/* populate opp power domains(for rails) */
+	rc = devm_pm_opp_attach_genpd(&core->pdev->dev, opp_tbl, &opp_vdevs);
+	if (rc)
+		return rc;
+
+	/* create device_links b/w consumer(dev) and multiple suppliers(mx, mmcx) */
+	for (cnt = 0; cnt < opp_count; cnt++) {
+		rc = devm_opp_dl_get(&core->pdev->dev, opp_vdevs[cnt]);
+		if (rc) {
+			d_vpr_e("%s: failed to create dl: %s\n",
+				__func__, dev_name(opp_vdevs[cnt]));
+			return rc;
+		}
+	}
+
+	/* initialize opp table from device tree */
+	rc = devm_pm_opp_of_add_table(&core->pdev->dev);
+	if (rc) {
+		d_vpr_e("%s: failed to add opp table\n", __func__);
+		return rc;
+	}
+
+	/**
+	 * 1. power up mx & mmcx supply for RCG(mvs0_clk_src)
+	 * 2. power up gdsc0c for mvs0c branch clk
+	 * 3. power up gdsc0 for mvs0 branch clk
+	 */
+
+	/**
+	 * power up mxc, mmcx rails to enable supply for
+	 * RCG(video_cc_mvs0_clk_src)
+	 */
+	/* enable runtime pm */
+	rc = devm_pm_runtime_enable(&core->pdev->dev);
+	if (rc) {
+		d_vpr_e("%s: failed to enable runtime pm\n", __func__);
+		return rc;
+	}
+	/* power up rails(mxc & mmcx) */
+	rc = devm_pm_runtime_get_sync(&core->pdev->dev);
+	if (rc) {
+		d_vpr_e("%s: failed to get sync runtime pm\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __init_clocks(struct msm_vidc_core *core)
+{
+	const struct clk_table *clk_tbl;
+	struct clock_set *clocks;
+	struct clock_info *cinfo = NULL;
+	u32 clk_count = 0, cnt = 0;
+	int rc = 0;
+
+	clocks = &core->resource->clock_set;
+
+	clk_tbl = core->platform->data.clk_tbl;
+	clk_count = core->platform->data.clk_tbl_size;
+
+	if (!clk_tbl || !clk_count) {
+		d_vpr_e("%s: invalid clock tbl %p or count %d\n",
+			__func__, clk_tbl, clk_count);
+		return -EINVAL;
+	}
+
+	/* allocate clock_set */
+	clocks->clock_tbl = devm_kzalloc(&core->pdev->dev,
+					 sizeof(*clocks->clock_tbl) * clk_count,
+					 GFP_KERNEL);
+	if (!clocks->clock_tbl) {
+		d_vpr_e("%s: failed to alloc memory for clock table\n", __func__);
+		return -ENOMEM;
+	}
+	clocks->count = clk_count;
+
+	/* populate clock field from platform data */
+	for (cnt = 0; cnt < clocks->count; cnt++) {
+		clocks->clock_tbl[cnt].name = clk_tbl[cnt].name;
+		clocks->clock_tbl[cnt].clk_id = clk_tbl[cnt].clk_id;
+		clocks->clock_tbl[cnt].has_scaling = clk_tbl[cnt].scaling;
+	}
+
+	/* print clock fields */
+	venus_hfi_for_each_clock(core, cinfo) {
+		d_vpr_h("%s: clock name %s clock id %#x scaling %d\n",
+			__func__, cinfo->name, cinfo->clk_id, cinfo->has_scaling);
+	}
+
+	/* get clock handle */
+	venus_hfi_for_each_clock(core, cinfo) {
+		cinfo->clk = devm_clk_get(&core->pdev->dev, cinfo->name);
+		if (IS_ERR_OR_NULL(cinfo->clk)) {
+			d_vpr_e("%s: failed to get clock: %s\n", __func__, cinfo->name);
+			rc = PTR_ERR_OR_ZERO(cinfo->clk) ?
+				PTR_ERR_OR_ZERO(cinfo->clk) : -EINVAL;
+			cinfo->clk = NULL;
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __init_reset_clocks(struct msm_vidc_core *core)
+{
+	const struct clk_rst_table *rst_tbl;
+	struct reset_set *rsts;
+	struct reset_info *rinfo = NULL;
+	u32 rst_count = 0, cnt = 0;
+	int rc = 0;
+
+	rsts = &core->resource->reset_set;
+
+	rst_tbl = core->platform->data.clk_rst_tbl;
+	rst_count = core->platform->data.clk_rst_tbl_size;
+
+	if (!rst_tbl || !rst_count) {
+		d_vpr_e("%s: invalid reset tbl %p or count %d\n",
+			__func__, rst_tbl, rst_count);
+		return -EINVAL;
+	}
+
+	/* allocate reset_set */
+	rsts->reset_tbl = devm_kzalloc(&core->pdev->dev,
+				       sizeof(*rsts->reset_tbl) * rst_count,
+				       GFP_KERNEL);
+	if (!rsts->reset_tbl) {
+		d_vpr_e("%s: failed to alloc memory for reset table\n", __func__);
+		return -ENOMEM;
+	}
+	rsts->count = rst_count;
+
+	/* populate clock field from platform data */
+	for (cnt = 0; cnt < rsts->count; cnt++) {
+		rsts->reset_tbl[cnt].name = rst_tbl[cnt].name;
+		rsts->reset_tbl[cnt].exclusive_release = rst_tbl[cnt].exclusive_release;
+	}
+
+	/* print reset clock fields */
+	venus_hfi_for_each_reset_clock(core, rinfo) {
+		d_vpr_h("%s: reset clk %s, exclusive %d\n",
+			__func__, rinfo->name, rinfo->exclusive_release);
+	}
+
+	/* get reset clock handle */
+	venus_hfi_for_each_reset_clock(core, rinfo) {
+		if (rinfo->exclusive_release)
+			rinfo->rst = devm_reset_control_get_exclusive_released(&core->pdev->dev,
+									       rinfo->name);
+		else
+			rinfo->rst = devm_reset_control_get(&core->pdev->dev, rinfo->name);
+		if (IS_ERR_OR_NULL(rinfo->rst)) {
+			d_vpr_e("%s: failed to get reset clock: %s\n", __func__, rinfo->name);
+			rc = PTR_ERR_OR_ZERO(rinfo->rst) ?
+				PTR_ERR_OR_ZERO(rinfo->rst) : -EINVAL;
+			rinfo->rst = NULL;
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __init_subcaches(struct msm_vidc_core *core)
+{
+	const struct subcache_table *llcc_tbl;
+	struct subcache_set *caches;
+	struct subcache_info *sinfo = NULL;
+	u32 llcc_count = 0, cnt = 0;
+	int rc = 0;
+
+	caches = &core->resource->subcache_set;
+
+	/* skip init if subcache not available */
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	llcc_tbl = core->platform->data.subcache_tbl;
+	llcc_count = core->platform->data.subcache_tbl_size;
+
+	if (!llcc_tbl || !llcc_count) {
+		d_vpr_e("%s: invalid llcc tbl %p or count %d\n",
+			__func__, llcc_tbl, llcc_count);
+		return -EINVAL;
+	}
+
+	/* allocate clock_set */
+	caches->subcache_tbl = devm_kzalloc(&core->pdev->dev,
+					    sizeof(*caches->subcache_tbl) * llcc_count,
+					    GFP_KERNEL);
+	if (!caches->subcache_tbl) {
+		d_vpr_e("%s: failed to alloc memory for subcache table\n", __func__);
+		return -ENOMEM;
+	}
+	caches->count = llcc_count;
+
+	/* populate subcache fields from platform data */
+	for (cnt = 0; cnt < caches->count; cnt++) {
+		caches->subcache_tbl[cnt].name = llcc_tbl[cnt].name;
+		caches->subcache_tbl[cnt].llcc_id = llcc_tbl[cnt].llcc_id;
+	}
+
+	/* print subcache fields */
+	venus_hfi_for_each_subcache(core, sinfo) {
+		d_vpr_h("%s: name %s subcache id %d\n",
+			__func__, sinfo->name, sinfo->llcc_id);
+	}
+
+	/* get subcache/llcc handle */
+	venus_hfi_for_each_subcache(core, sinfo) {
+		sinfo->subcache = devm_llcc_get(&core->pdev->dev, sinfo->llcc_id);
+		if (IS_ERR_OR_NULL(sinfo->subcache)) {
+			d_vpr_e("%s: failed to get subcache: %d\n", __func__, sinfo->llcc_id);
+			rc = PTR_ERR_OR_ZERO(sinfo->subcache) ?
+				PTR_ERR_OR_ZERO(sinfo->subcache) : -EBADHANDLE;
+			sinfo->subcache = NULL;
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __init_freq_table(struct msm_vidc_core *core)
+{
+	struct freq_table *freq_tbl;
+	struct freq_set *clks;
+	u32 freq_count = 0, cnt = 0;
+	int rc = 0;
+
+	clks = &core->resource->freq_set;
+
+	freq_tbl = core->platform->data.freq_tbl;
+	freq_count = core->platform->data.freq_tbl_size;
+
+	if (!freq_tbl || !freq_count) {
+		d_vpr_e("%s: invalid freq tbl %p or count %d\n",
+			__func__, freq_tbl, freq_count);
+		return -EINVAL;
+	}
+
+	/* allocate freq_set */
+	clks->freq_tbl = devm_kzalloc(&core->pdev->dev,
+				      sizeof(*clks->freq_tbl) * freq_count,
+				      GFP_KERNEL);
+	if (!clks->freq_tbl) {
+		d_vpr_e("%s: failed to alloc memory for freq table\n", __func__);
+		return -ENOMEM;
+	}
+	clks->count = freq_count;
+
+	/* populate freq field from platform data */
+	for (cnt = 0; cnt < clks->count; cnt++)
+		clks->freq_tbl[cnt].freq = freq_tbl[cnt].freq;
+
+	/* sort freq table */
+	sort(clks->freq_tbl, clks->count, sizeof(*clks->freq_tbl), cmp, NULL);
+
+	/* print freq field freq_set */
+	d_vpr_h("%s: updated freq table\n", __func__);
+	for (cnt = 0; cnt < clks->count; cnt++)
+		d_vpr_h("%s:\t %lu\n", __func__, clks->freq_tbl[cnt].freq);
+
+	return rc;
+}
+
+static int __init_context_banks(struct msm_vidc_core *core)
+{
+	const struct context_bank_table *cb_tbl;
+	struct context_bank_set *cbs;
+	struct context_bank_info *cbinfo = NULL;
+	u32 cb_count = 0, cnt = 0;
+	int rc = 0;
+
+	cbs = &core->resource->context_bank_set;
+
+	cb_tbl = core->platform->data.context_bank_tbl;
+	cb_count = core->platform->data.context_bank_tbl_size;
+
+	if (!cb_tbl || !cb_count) {
+		d_vpr_e("%s: invalid context bank tbl %p or count %d\n",
+			__func__, cb_tbl, cb_count);
+		return -EINVAL;
+	}
+
+	/* allocate context_bank table */
+	cbs->context_bank_tbl = devm_kzalloc(&core->pdev->dev,
+					     sizeof(*cbs->context_bank_tbl) * cb_count,
+					     GFP_KERNEL);
+	if (!cbs->context_bank_tbl) {
+		d_vpr_e("%s: failed to alloc memory for context_bank table\n", __func__);
+		return -ENOMEM;
+	}
+	cbs->count = cb_count;
+
+	/**
+	 * populate context bank field from platform data except
+	 * dev & domain which are assigned as part of context bank
+	 * probe sequence
+	 */
+	for (cnt = 0; cnt < cbs->count; cnt++) {
+		cbs->context_bank_tbl[cnt].name = cb_tbl[cnt].name;
+		cbs->context_bank_tbl[cnt].addr_range.start = cb_tbl[cnt].start;
+		cbs->context_bank_tbl[cnt].addr_range.size = cb_tbl[cnt].size;
+		cbs->context_bank_tbl[cnt].secure = cb_tbl[cnt].secure;
+		cbs->context_bank_tbl[cnt].dma_coherant = cb_tbl[cnt].dma_coherant;
+		cbs->context_bank_tbl[cnt].region = cb_tbl[cnt].region;
+		cbs->context_bank_tbl[cnt].dma_mask = cb_tbl[cnt].dma_mask;
+	}
+
+	/* print context_bank fiels */
+	venus_hfi_for_each_context_bank(core, cbinfo) {
+		d_vpr_h("%s: name %s addr start %#x size %#x secure %d\n",
+			__func__, cbinfo->name, cbinfo->addr_range.start,
+			cbinfo->addr_range.size, cbinfo->secure);
+
+		d_vpr_h("%s: coherant %d region %d dma_mask %llu\n",
+			__func__, cbinfo->dma_coherant, cbinfo->region,
+			cbinfo->dma_mask);
+	}
+
+	return rc;
+}
+
+static int __enable_power_domains(struct msm_vidc_core *core, const char *name)
+{
+	struct power_domain_info *pdinfo = NULL;
+	int rc = 0;
+
+	/* power up rails(mxc & mmcx) to enable RCG(video_cc_mvs0_clk_src) */
+	rc = __opp_set_rate(core, ULONG_MAX);
+	if (rc) {
+		d_vpr_e("%s: opp setrate failed\n", __func__);
+		return rc;
+	}
+
+	/* power up (gdsc0/gdsc0c) to enable (mvs0/mvs0c) branch clock */
+	venus_hfi_for_each_power_domain(core, pdinfo) {
+		if (strcmp(pdinfo->name, name))
+			continue;
+
+		rc = pm_runtime_get_sync(pdinfo->genpd_dev);
+		if (rc < 0) {
+			d_vpr_e("%s: failed to get sync: %s\n", __func__, pdinfo->name);
+			return rc;
+		}
+		d_vpr_h("%s: enabled power doamin %s\n", __func__, pdinfo->name);
+	}
+
+	return rc;
+}
+
+static int __disable_power_domains(struct msm_vidc_core *core, const char *name)
+{
+	struct power_domain_info *pdinfo = NULL;
+	int rc = 0;
+
+	/* power down (gdsc0/gdsc0c) to disable (mvs0/mvs0c) branch clock */
+	venus_hfi_for_each_power_domain(core, pdinfo) {
+		if (strcmp(pdinfo->name, name))
+			continue;
+
+		rc = pm_runtime_put_sync(pdinfo->genpd_dev);
+		if (rc) {
+			d_vpr_e("%s: failed to put sync: %s\n", __func__, pdinfo->name);
+			return rc;
+		}
+		d_vpr_h("%s: disabled power doamin %s\n", __func__, pdinfo->name);
+	}
+
+	/* power down rails(mxc & mmcx) to disable RCG(video_cc_mvs0_clk_src) */
+	rc = __opp_set_rate(core, 0);
+	if (rc) {
+		d_vpr_e("%s: opp setrate failed\n", __func__);
+		return rc;
+	}
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
+
+	return rc;
+}
+
+static int __hand_off_power_domains(struct msm_vidc_core *core)
+{
+	msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_GDSC_HANDOFF, __func__);
+
+	return 0;
+}
+
+static int __acquire_power_domains(struct msm_vidc_core *core)
+{
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
+
+	return 0;
+}
+
+static int __disable_subcaches(struct msm_vidc_core *core)
+{
+	struct subcache_info *sinfo;
+	int rc = 0;
+
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	/* De-activate subcaches */
+	venus_hfi_for_each_subcache_reverse(core, sinfo) {
+		if (!sinfo->isactive)
+			continue;
+
+		d_vpr_h("%s: De-activate subcache %s\n", __func__, sinfo->name);
+		rc = llcc_slice_deactivate(sinfo->subcache);
+		if (rc) {
+			d_vpr_e("Failed to de-activate %s: %d\n",
+				sinfo->name, rc);
+		}
+		sinfo->isactive = false;
+	}
+
+	return 0;
+}
+
+static int __enable_subcaches(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u32 c = 0;
+	struct subcache_info *sinfo;
+
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	/* Activate subcaches */
+	venus_hfi_for_each_subcache(core, sinfo) {
+		rc = llcc_slice_activate(sinfo->subcache);
+		if (rc) {
+			d_vpr_e("Failed to activate %s: %d\n", sinfo->name, rc);
+			__fatal_error(true);
+			goto err_activate_fail;
+		}
+		sinfo->isactive = true;
+		d_vpr_h("Activated subcache %s\n", sinfo->name);
+		c++;
+	}
+
+	d_vpr_h("Activated %d Subcaches to Venus\n", c);
+
+	return 0;
+
+err_activate_fail:
+	__disable_subcaches(core);
+	return rc;
+}
+
+static int llcc_enable(struct msm_vidc_core *core, bool enable)
+{
+	int ret;
+
+	if (enable)
+		ret = __enable_subcaches(core);
+	else
+		ret = __disable_subcaches(core);
+
+	return ret;
+}
+
+static int __vote_bandwidth(struct bus_info *bus, unsigned long bw_kbps)
+{
+	int rc = 0;
+
+	if (!bus->icc) {
+		d_vpr_e("%s: invalid bus\n", __func__);
+		return -EINVAL;
+	}
+
+	d_vpr_p("Voting bus %s to ab %lu kBps\n", bus->name, bw_kbps);
+
+	rc = icc_set_bw(bus->icc, bw_kbps, 0);
+	if (rc)
+		d_vpr_e("Failed voting bus %s to ab %lu, rc=%d\n",
+			bus->name, bw_kbps, rc);
+
+	return rc;
+}
+
+static int __unvote_buses(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+
+	core->power.bw_ddr = 0;
+	core->power.bw_llcc = 0;
+
+	venus_hfi_for_each_bus(core, bus) {
+		rc = __vote_bandwidth(bus, 0);
+		if (rc)
+			goto err_unknown_device;
+	}
+
+err_unknown_device:
+	return rc;
+}
+
+static int __vote_buses(struct msm_vidc_core *core,
+			unsigned long bw_ddr, unsigned long bw_llcc)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+	unsigned long bw_kbps = 0, bw_prev = 0;
+	enum vidc_bus_type type;
+
+	venus_hfi_for_each_bus(core, bus) {
+		if (bus && bus->icc) {
+			type = get_type_frm_name(bus->name);
+
+			if (type == DDR) {
+				bw_kbps = bw_ddr;
+				bw_prev = core->power.bw_ddr;
+			} else if (type == LLCC) {
+				bw_kbps = bw_llcc;
+				bw_prev = core->power.bw_llcc;
+			} else {
+				bw_kbps = bus->max_kbps;
+				bw_prev = core->power.bw_ddr ?
+						bw_kbps : 0;
+			}
+
+			/* ensure freq is within limits */
+			bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps,
+					  bus->min_kbps, bus->max_kbps);
+
+			if (TRIVIAL_BW_CHANGE(bw_kbps, bw_prev) && bw_prev) {
+				d_vpr_l("Skip voting bus %s to %lu kBps\n",
+					bus->name, bw_kbps);
+				continue;
+			}
+
+			rc = __vote_bandwidth(bus, bw_kbps);
+
+			if (type == DDR)
+				core->power.bw_ddr = bw_kbps;
+			else if (type == LLCC)
+				core->power.bw_llcc = bw_kbps;
+		} else {
+			d_vpr_e("No BUS to Vote\n");
+		}
+	}
+
+	return rc;
+}
+
+static int set_bw(struct msm_vidc_core *core, unsigned long bw_ddr,
+		  unsigned long bw_llcc)
+{
+	if (!bw_ddr && !bw_llcc)
+		return __unvote_buses(core);
+
+	return __vote_buses(core, bw_ddr, bw_llcc);
+}
+
+static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl,
+			  u64 rate)
+{
+	int rc = 0;
+
+	/* bail early if requested clk rate is not changed */
+	if (rate == cl->prev)
+		return 0;
+
+	d_vpr_p("Scaling clock %s to %llu, prev %llu\n",
+		cl->name, rate, cl->prev);
+
+	rc = clk_set_rate(cl->clk, rate);
+	if (rc) {
+		d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n",
+			__func__, rate, cl->name, rc);
+		return rc;
+	}
+
+	cl->prev = rate;
+
+	return rc;
+}
+
+static int __set_clocks(struct msm_vidc_core *core, u64 freq)
+{
+	struct clock_info *cl;
+	int rc = 0;
+
+	/* scale mxc & mmcx rails */
+	rc = __opp_set_rate(core, freq);
+	if (rc) {
+		d_vpr_e("%s: opp setrate failed %lld\n", __func__, freq);
+		return rc;
+	}
+
+	venus_hfi_for_each_clock(core, cl) {
+		if (cl->has_scaling) {
+			rc = __set_clk_rate(core, cl, freq);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int __disable_unprepare_clock(struct msm_vidc_core *core,
+				     const char *clk_name)
+{
+	int rc = 0;
+	struct clock_info *cl;
+	bool found;
+
+	found = false;
+	venus_hfi_for_each_clock(core, cl) {
+		if (!cl->clk) {
+			d_vpr_e("%s: invalid clock %s\n", __func__, cl->name);
+			return -EINVAL;
+		}
+		if (strcmp(cl->name, clk_name))
+			continue;
+		found = true;
+		clk_disable_unprepare(cl->clk);
+		if (cl->has_scaling)
+			__set_clk_rate(core, cl, 0);
+		cl->prev = 0;
+		d_vpr_h("%s: clock %s disable unprepared\n", __func__, cl->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __prepare_enable_clock(struct msm_vidc_core *core,
+				  const char *clk_name)
+{
+	int rc = 0;
+	struct clock_info *cl;
+	bool found;
+	u64 rate = 0;
+
+	found = false;
+	venus_hfi_for_each_clock(core, cl) {
+		if (!cl->clk) {
+			d_vpr_e("%s: invalid clock\n", __func__);
+			return -EINVAL;
+		}
+		if (strcmp(cl->name, clk_name))
+			continue;
+		found = true;
+		/*
+		 * 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->has_scaling) {
+			rate = clk_round_rate(cl->clk, 0);
+			/**
+			 * source clock is already multipled with scaling ratio and __set_clk_rate
+			 * attempts to multiply again. So divide scaling ratio before calling
+			 * __set_clk_rate.
+			 */
+			rate = rate / MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
+			__set_clk_rate(core, cl, rate);
+		}
+
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			d_vpr_e("%s: failed to enable clock %s\n",
+				__func__, cl->name);
+			return rc;
+		}
+		if (!__clk_is_enabled(cl->clk)) {
+			d_vpr_e("%s: clock %s not enabled\n",
+				__func__, cl->name);
+			clk_disable_unprepare(cl->clk);
+			if (cl->has_scaling)
+				__set_clk_rate(core, cl, 0);
+			return -EINVAL;
+		}
+		d_vpr_h("%s: clock %s prepare enabled\n", __func__, cl->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __init_resources(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = __init_register_base(core);
+	if (rc)
+		return rc;
+
+	rc = __init_irq(core);
+	if (rc)
+		return rc;
+
+	rc = __init_bus(core);
+	if (rc)
+		return rc;
+
+	rc = call_res_op(core, gdsc_init, core);
+	if (rc)
+		return rc;
+
+	rc = __init_clocks(core);
+	if (rc)
+		return rc;
+
+	rc = __init_reset_clocks(core);
+	if (rc)
+		return rc;
+
+	rc = __init_subcaches(core);
+	if (rc)
+		return rc;
+
+	rc = __init_freq_table(core);
+	if (rc)
+		return rc;
+
+	rc = __init_context_banks(core);
+
+	return rc;
+}
+
+static int __reset_control_acquire_name(struct msm_vidc_core *core,
+					const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+
+		/* this function is valid only for exclusive_release reset clocks*/
+		if (!rcinfo->exclusive_release) {
+			d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n",
+				__func__, name, rcinfo->exclusive_release);
+			return -EINVAL;
+		}
+
+		found = true;
+
+		rc = reset_control_acquire(rcinfo->rst);
+		if (rc)
+			d_vpr_e("%s: failed to acquire reset control (%s), rc = %d\n",
+				__func__, rcinfo->name, rc);
+		else
+			d_vpr_h("%s: acquire reset control (%s)\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __reset_control_release_name(struct msm_vidc_core *core,
+					const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+
+		/* this function is valid only for exclusive_release reset clocks*/
+		if (!rcinfo->exclusive_release) {
+			d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n",
+				__func__, name, rcinfo->exclusive_release);
+			return -EINVAL;
+		}
+
+		found = true;
+
+		reset_control_release(rcinfo->rst);
+		if (rc)
+			d_vpr_e("%s: release reset control (%s) failed\n",
+				__func__, rcinfo->name);
+		else
+			d_vpr_h("%s: release reset control (%s) done\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __reset_control_assert_name(struct msm_vidc_core *core,
+				       const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+
+		found = true;
+		rc = reset_control_assert(rcinfo->rst);
+		if (rc)
+			d_vpr_e("%s: failed to assert reset control (%s), rc = %d\n",
+				__func__, rcinfo->name, rc);
+		else
+			d_vpr_h("%s: assert reset control (%s)\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __reset_control_deassert_name(struct msm_vidc_core *core,
+					 const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+		found = true;
+		rc = reset_control_deassert(rcinfo->rst);
+		if (rc)
+			d_vpr_e("%s: deassert reset control for (%s) failed, rc %d\n",
+				__func__, rcinfo->name, rc);
+		else
+			d_vpr_h("%s: deassert reset control (%s)\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __reset_control_deassert(struct msm_vidc_core *core)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		rc = reset_control_deassert(rcinfo->rst);
+		if (rc) {
+			d_vpr_e("%s: deassert reset control failed. rc = %d\n", __func__, rc);
+			continue;
+		}
+		d_vpr_h("%s: deassert reset control %s\n", __func__, rcinfo->name);
+	}
+
+	return rc;
+}
+
+static int __reset_control_assert(struct msm_vidc_core *core)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0, cnt = 0;
+
+	venus_hfi_for_each_reset_clock(core, rcinfo) {
+		if (!rcinfo->rst) {
+			d_vpr_e("%s: invalid reset clock %s\n",
+				__func__, rcinfo->name);
+			return -EINVAL;
+		}
+		rc = reset_control_assert(rcinfo->rst);
+		if (rc) {
+			d_vpr_e("%s: failed to assert reset control %s, rc = %d\n",
+				__func__, rcinfo->name, rc);
+			goto deassert_reset_control;
+		}
+		cnt++;
+		d_vpr_h("%s: assert reset control %s, count %d\n", __func__, rcinfo->name, cnt);
+
+		usleep_range(1000, 1100);
+	}
+
+	return rc;
+deassert_reset_control:
+	venus_hfi_for_each_reset_clock_reverse_continue(core, rcinfo, cnt) {
+		d_vpr_e("%s: deassert reset control %s\n", __func__, rcinfo->name);
+		reset_control_deassert(rcinfo->rst);
+	}
+
+	return rc;
+}
+
+static int __reset_ahb2axi_bridge(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = __reset_control_assert(core);
+	if (rc)
+		return rc;
+
+	rc = __reset_control_deassert(core);
+
+	return rc;
+}
+
+static const struct msm_vidc_resources_ops res_ops = {
+	.init = __init_resources,
+	.reset_bridge = __reset_ahb2axi_bridge,
+	.reset_control_acquire = __reset_control_acquire_name,
+	.reset_control_release = __reset_control_release_name,
+	.reset_control_assert = __reset_control_assert_name,
+	.reset_control_deassert = __reset_control_deassert_name,
+	.gdsc_init = __init_power_domains,
+	.gdsc_on = __enable_power_domains,
+	.gdsc_off = __disable_power_domains,
+	.gdsc_hw_ctrl = __hand_off_power_domains,
+	.gdsc_sw_ctrl = __acquire_power_domains,
+	.llcc = llcc_enable,
+	.set_bw = set_bw,
+	.set_clks = __set_clocks,
+	.clk_enable = __prepare_enable_clock,
+	.clk_disable = __disable_unprepare_clock,
+};
+
+const struct msm_vidc_resources_ops *get_resources_ops(void)
+{
+	return &res_ops;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 13/33] iris: vidc: add helper functions for power management
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (11 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 12/33] iris: vidc: add helper functions for resource management Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:46   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 14/33] iris: vidc: add helpers for state management Vikash Garodia
                   ` (22 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

this implements functions for calculating current load of the
hardware. Depending on the count of instances and
resolutions it selects the best clock rate for the video
core. Also it scales clocks, power and enable/disable dcvs.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_power.h   |  94 ++++
 .../platform/qcom/iris/vidc/src/msm_vidc_power.c   | 560 +++++++++++++++++++++
 2 files changed, 654 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
new file mode 100644
index 0000000..cb424f5
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_POWER_H_
+#define _MSM_VIDC_POWER_H_
+
+#include "msm_vidc_debug.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+#define COMPRESSION_RATIO_MAX 5
+
+/* TODO: Move to dtsi OR use source clock instead of branch clock.*/
+#define MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO 3
+
+enum vidc_bus_type {
+	PERF,
+	DDR,
+	LLCC,
+};
+
+/*
+ * Minimum dimensions for which to calculate bandwidth.
+ * This means that anything bandwidth(0, 0) ==
+ * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
+ */
+static const struct {
+	int height, width;
+} BASELINE_DIMENSIONS = {
+	.width = 1280,
+	.height = 720,
+};
+
+/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
+#define kbps(__mbps) ((__mbps) * 1000)
+#define bps(__mbps) (kbps(__mbps) * 1000)
+
+static inline u32 get_type_frm_name(const char *name)
+{
+	if (!strcmp(name, "venus-llcc"))
+		return LLCC;
+	else if (!strcmp(name, "venus-ddr"))
+		return DDR;
+	else
+		return PERF;
+}
+
+#define DUMP_HEADER_MAGIC 0xdeadbeef
+#define DUMP_FP_FMT "%FP" /* special format for fp_t */
+
+struct dump {
+	char *key;
+	char *format;
+	size_t val;
+};
+
+void __dump(struct dump dump[], int len);
+
+static inline bool __ubwc(enum msm_vidc_colorformat_type f)
+{
+	switch (f) {
+	case MSM_VIDC_FMT_NV12C:
+	case MSM_VIDC_FMT_TP10C:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline int __bpp(enum msm_vidc_colorformat_type f)
+{
+	switch (f) {
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12C:
+	case MSM_VIDC_FMT_RGBA8888C:
+		return 8;
+	case MSM_VIDC_FMT_P010:
+	case MSM_VIDC_FMT_TP10C:
+		return 10;
+	default:
+		d_vpr_e("Unsupported colorformat (%x)", f);
+		return INT_MAX;
+	}
+}
+
+u64 msm_vidc_max_freq(struct msm_vidc_inst *inst);
+int msm_vidc_scale_power(struct msm_vidc_inst *inst, bool scale_buses);
+void msm_vidc_power_data_reset(struct msm_vidc_inst *inst);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
new file mode 100644
index 0000000..cb5c7b7c
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_buffer.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "venus_hfi.h"
+
+/* Q16 Format */
+#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16)
+#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16)
+#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16)
+#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16)
+
+void __dump(struct dump dump[], int len)
+{
+	int c = 0;
+
+	for (c = 0; c < len; ++c) {
+		char format_line[128] = "", formatted_line[128] = "";
+
+		if (dump[c].val == DUMP_HEADER_MAGIC) {
+			snprintf(formatted_line, sizeof(formatted_line), "%s\n",
+				 dump[c].key);
+		} else {
+			snprintf(format_line, sizeof(format_line),
+				 "    %-35s: %s\n", dump[c].key,
+					 dump[c].format);
+			snprintf(formatted_line, sizeof(formatted_line),
+				 format_line, dump[c].val);
+		}
+		d_vpr_b("%s", formatted_line);
+	}
+}
+
+u64 msm_vidc_max_freq(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct frequency_table *freq_tbl;
+	u64 freq = 0;
+
+	core = inst->core;
+
+	if (!core->resource || !core->resource->freq_set.freq_tbl ||
+	    !core->resource->freq_set.count) {
+		i_vpr_e(inst, "%s: invalid frequency table\n", __func__);
+		return freq;
+	}
+	freq_tbl = core->resource->freq_set.freq_tbl;
+	freq = freq_tbl[0].freq;
+
+	i_vpr_l(inst, "%s: rate = %llu\n", __func__, freq);
+	return freq;
+}
+
+static int fill_dynamic_stats(struct msm_vidc_inst *inst,
+			      struct vidc_bus_vote_data *vote_data)
+{
+	struct msm_vidc_input_cr_data *temp, *next;
+	u32 cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
+	u32 cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO;
+	u32 input_cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO;
+	u32 frame_size;
+
+	if (inst->power.fw_cr)
+		cr = inst->power.fw_cr;
+
+	if (inst->power.fw_cf) {
+		cf = inst->power.fw_cf;
+		frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2;
+		if (frame_size)
+			cf = cf / frame_size;
+	}
+
+	list_for_each_entry_safe(temp, next, &inst->enc_input_crs, list)
+		input_cr = min(input_cr, temp->input_cr);
+
+	vote_data->compression_ratio = cr;
+	vote_data->complexity_factor = cf;
+	vote_data->input_cr = input_cr;
+
+	/* Sanitize CF values from HW */
+	cf = clamp_t(u32, cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR,
+		     MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR);
+	cr = clamp_t(u32, cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO,
+		     MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+	input_cr = clamp_t(u32, input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO,
+			   MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO);
+
+	vote_data->compression_ratio = cr;
+	vote_data->complexity_factor = cf;
+	vote_data->input_cr = input_cr;
+
+	i_vpr_l(inst,
+		"Input CR = %d Recon CR = %d Complexity Factor = %d\n",
+		vote_data->input_cr, vote_data->compression_ratio,
+		vote_data->complexity_factor);
+
+	return 0;
+}
+
+static int msm_vidc_set_buses(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *temp;
+	u64 total_bw_ddr = 0, total_bw_llcc = 0;
+	u64 curr_time_ns;
+
+	core = inst->core;
+
+	mutex_lock(&core->lock);
+	curr_time_ns = ktime_get_ns();
+	list_for_each_entry(temp, &core->instances, list) {
+		/* skip for session where no input is there to process */
+		if (!temp->max_input_data_size)
+			continue;
+
+		/* skip inactive session bus bandwidth */
+		if (!is_active_session(temp->last_qbuf_time_ns, curr_time_ns)) {
+			temp->active = false;
+			continue;
+		}
+
+		if (temp->power.power_mode == VIDC_POWER_TURBO) {
+			total_bw_ddr = INT_MAX;
+			total_bw_llcc = INT_MAX;
+			break;
+		}
+
+		total_bw_ddr += temp->power.ddr_bw;
+		total_bw_llcc += temp->power.sys_cache_bw;
+	}
+	mutex_unlock(&core->lock);
+
+	rc = venus_hfi_scale_buses(inst, total_bw_ddr, total_bw_llcc);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vidc_scale_buses(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct vidc_bus_vote_data *vote_data;
+	struct v4l2_format *out_f;
+	struct v4l2_format *inp_f;
+	u32 operating_rate, frame_rate;
+
+	core = inst->core;
+	if (!core->resource) {
+		i_vpr_e(inst, "%s: invalid resource params\n", __func__);
+		return -EINVAL;
+	}
+	vote_data = &inst->bus_data;
+
+	vote_data->power_mode = VIDC_POWER_NORMAL;
+	if (inst->power.buffer_counter < DCVS_WINDOW)
+		vote_data->power_mode = VIDC_POWER_TURBO;
+
+	if (vote_data->power_mode == VIDC_POWER_TURBO)
+		goto set_buses;
+
+	out_f = &inst->fmts[OUTPUT_PORT];
+	inp_f = &inst->fmts[INPUT_PORT];
+
+	vote_data->codec = inst->codec;
+	vote_data->input_width = inp_f->fmt.pix_mp.width;
+	vote_data->input_height = inp_f->fmt.pix_mp.height;
+	vote_data->output_width = out_f->fmt.pix_mp.width;
+	vote_data->output_height = out_f->fmt.pix_mp.height;
+	vote_data->lcu_size = (inst->codec == MSM_VIDC_HEVC ||
+			inst->codec == MSM_VIDC_VP9) ? 32 : 16;
+	vote_data->fps = inst->max_rate;
+
+	if (is_encode_session(inst)) {
+		vote_data->domain = MSM_VIDC_ENCODER;
+		vote_data->bitrate = inst->capabilities[BIT_RATE].value;
+		vote_data->rotation = inst->capabilities[ROTATION].value;
+		vote_data->b_frames_enabled =
+			inst->capabilities[B_FRAME].value > 0;
+
+		/* scale bitrate if operating rate is larger than frame rate */
+		frame_rate = msm_vidc_get_frame_rate(inst);
+		operating_rate = inst->max_rate;
+		if (frame_rate && operating_rate && operating_rate > frame_rate)
+			vote_data->bitrate = (vote_data->bitrate / frame_rate) * operating_rate;
+
+		vote_data->num_formats = 1;
+		vote_data->color_formats[0] =
+			v4l2_colorformat_to_driver(inst,
+						   inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat,
+						   __func__);
+	} else if (is_decode_session(inst)) {
+		u32 color_format;
+
+		vote_data->domain = MSM_VIDC_DECODER;
+		vote_data->bitrate = inst->max_input_data_size * vote_data->fps * 8;
+		color_format =
+			v4l2_colorformat_to_driver(inst,
+						   inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
+						   __func__);
+		if (is_linear_colorformat(color_format)) {
+			vote_data->num_formats = 2;
+			/*
+			 * 0 index - dpb colorformat
+			 * 1 index - opb colorformat
+			 */
+			if (is_10bit_colorformat(color_format))
+				vote_data->color_formats[0] = MSM_VIDC_FMT_TP10C;
+			else
+				vote_data->color_formats[0] = MSM_VIDC_FMT_NV12;
+			vote_data->color_formats[1] = color_format;
+		} else {
+			vote_data->num_formats = 1;
+			vote_data->color_formats[0] = color_format;
+		}
+	}
+	vote_data->work_mode = inst->capabilities[STAGE].value;
+	if (core->resource->subcache_set.set_to_fw)
+		vote_data->use_sys_cache = true;
+	vote_data->num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+	fill_dynamic_stats(inst, vote_data);
+
+	call_session_op(core, calc_bw, inst, vote_data);
+
+	inst->power.ddr_bw = vote_data->calc_bw_ddr;
+	inst->power.sys_cache_bw = vote_data->calc_bw_llcc;
+
+	if (!inst->stats.avg_bw_llcc)
+		inst->stats.avg_bw_llcc = inst->power.sys_cache_bw;
+	else
+		inst->stats.avg_bw_llcc =
+			(inst->stats.avg_bw_llcc + inst->power.sys_cache_bw) / 2;
+
+	if (!inst->stats.avg_bw_ddr)
+		inst->stats.avg_bw_ddr = inst->power.ddr_bw;
+	else
+		inst->stats.avg_bw_ddr =
+			(inst->stats.avg_bw_ddr + inst->power.ddr_bw) / 2;
+
+set_buses:
+	inst->power.power_mode = vote_data->power_mode;
+	rc = msm_vidc_set_buses(inst);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_vidc_set_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *temp;
+	u64 freq;
+	u64 rate = 0;
+	bool increment, decrement;
+	u64 curr_time_ns;
+	int i = 0;
+
+	core = inst->core;
+
+	if (!core->resource || !core->resource->freq_set.freq_tbl ||
+	    !core->resource->freq_set.count) {
+		d_vpr_e("%s: invalid frequency table\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	increment = false;
+	decrement = true;
+	freq = 0;
+	curr_time_ns = ktime_get_ns();
+	list_for_each_entry(temp, &core->instances, list) {
+		/* skip for session where no input is there to process */
+		if (!temp->max_input_data_size)
+			continue;
+
+		/* skip inactive session clock rate */
+		if (!is_active_session(temp->last_qbuf_time_ns, curr_time_ns)) {
+			temp->active = false;
+			continue;
+		}
+		freq += temp->power.min_freq;
+
+		/* increment even if one session requested for it */
+		if (temp->power.dcvs_flags & MSM_VIDC_DCVS_INCR)
+			increment = true;
+		/* decrement only if all sessions requested for it */
+		if (!(temp->power.dcvs_flags & MSM_VIDC_DCVS_DECR))
+			decrement = false;
+	}
+
+	/*
+	 * keep checking from lowest to highest rate until
+	 * table rate >= requested rate
+	 */
+	for (i = core->resource->freq_set.count - 1; i >= 0; i--) {
+		rate = core->resource->freq_set.freq_tbl[i].freq;
+		if (rate >= freq)
+			break;
+	}
+	if (i < 0)
+		i = 0;
+	if (increment) {
+		if (i > 0)
+			rate = core->resource->freq_set.freq_tbl[i - 1].freq;
+	} else if (decrement) {
+		if (i < (int)(core->platform->data.freq_tbl_size - 1))
+			rate = core->resource->freq_set.freq_tbl[i + 1].freq;
+	}
+	core->power.clk_freq = (u32)rate;
+
+	i_vpr_p(inst, "%s: clock rate %llu requested %llu increment %d decrement %d\n",
+		__func__, rate, freq, increment, decrement);
+	mutex_unlock(&core->lock);
+
+	rc = venus_hfi_scale_clocks(inst, rate);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int msm_vidc_apply_dcvs(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int bufs_with_fw = 0;
+	struct msm_vidc_power *power;
+
+	/* skip dcvs */
+	if (!inst->power.dcvs_mode)
+		return 0;
+
+	power = &inst->power;
+
+	if (is_decode_session(inst)) {
+		bufs_with_fw = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT,
+						    MSM_VIDC_ATTR_QUEUED);
+	} else {
+		bufs_with_fw = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_INPUT,
+						    MSM_VIDC_ATTR_QUEUED);
+	}
+
+	/* +1 as one buffer is going to be queued after the function */
+	bufs_with_fw += 1;
+
+	/*
+	 * DCVS decides clock level based on below algorithm
+	 *
+	 * Limits :
+	 * min_threshold : Buffers required for reference by FW.
+	 * nom_threshold : Midpoint of Min and Max thresholds
+	 * max_threshold : Min Threshold + DCVS extra buffers, allocated
+	 *				   for smooth flow.
+	 * 1) When buffers outside FW are reaching client's extra buffers,
+	 *    FW is slow and will impact pipeline, Increase clock.
+	 * 2) When pending buffers with FW are less than FW requested,
+	 *    pipeline has cushion to absorb FW slowness, Decrease clocks.
+	 * 3) When DCVS has engaged(Inc or Dec):
+	 *    For decode:
+	 *        - Pending buffers with FW transitions past the nom_threshold,
+	 *        switch to calculated load, this smoothens the clock transitions.
+	 *    For encode:
+	 *        - Always switch to calculated load.
+	 * 4) Otherwise maintain previous Load config.
+	 */
+	if (bufs_with_fw >= power->max_threshold) {
+		power->dcvs_flags = MSM_VIDC_DCVS_INCR;
+		goto exit;
+	} else if (bufs_with_fw < power->min_threshold) {
+		power->dcvs_flags = MSM_VIDC_DCVS_DECR;
+		goto exit;
+	}
+
+	/* encoder: dcvs window handling */
+	if (is_encode_session(inst)) {
+		power->dcvs_flags = 0;
+		goto exit;
+	}
+
+	/* decoder: dcvs window handling */
+	if ((power->dcvs_flags & MSM_VIDC_DCVS_DECR && bufs_with_fw >= power->nom_threshold) ||
+	    (power->dcvs_flags & MSM_VIDC_DCVS_INCR && bufs_with_fw <= power->nom_threshold)) {
+		power->dcvs_flags = 0;
+	}
+
+exit:
+	i_vpr_p(inst, "dcvs: bufs_with_fw %d th[%d %d %d] flags %#x\n",
+		bufs_with_fw, power->min_threshold,
+		power->nom_threshold, power->max_threshold,
+		power->dcvs_flags);
+
+	return rc;
+}
+
+int msm_vidc_scale_clocks(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (inst->power.buffer_counter < DCVS_WINDOW ||
+	    is_sub_state(inst, MSM_VIDC_DRC) ||
+	    is_sub_state(inst, MSM_VIDC_DRAIN)) {
+		inst->power.min_freq = msm_vidc_max_freq(inst);
+		inst->power.dcvs_flags = 0;
+	} else {
+		inst->power.min_freq =
+			call_session_op(core, calc_freq, inst, inst->max_input_data_size);
+		msm_vidc_apply_dcvs(inst);
+	}
+	inst->power.curr_freq = inst->power.min_freq;
+	msm_vidc_set_clocks(inst);
+
+	return 0;
+}
+
+int msm_vidc_scale_power(struct msm_vidc_inst *inst, bool scale_buses)
+{
+	struct msm_vidc_core *core;
+	struct msm_vidc_buffer *vbuf;
+	u32 data_size = 0;
+	u32 cnt = 0;
+	u32 fps;
+	u32 frame_rate, operating_rate;
+	u32 timestamp_rate = 0, input_rate = 0;
+
+	core = inst->core;
+
+	if (!inst->active) {
+		/* scale buses for inactive -> active session */
+		scale_buses = true;
+		inst->active = true;
+	}
+
+	/*
+	 * consider avg. filled length in decode batching case
+	 * to avoid overvoting for the entire batch due to single
+	 * frame with huge filled length
+	 */
+	if (inst->decode_batch.enable) {
+		list_for_each_entry(vbuf, &inst->buffers.input.list, list) {
+			if (vbuf->attr & MSM_VIDC_ATTR_DEFERRED ||
+			    vbuf->attr & MSM_VIDC_ATTR_QUEUED) {
+				data_size += vbuf->data_size;
+				cnt++;
+			}
+		}
+		if (cnt)
+			data_size /= cnt;
+	} else {
+		list_for_each_entry(vbuf, &inst->buffers.input.list, list)
+			data_size = max(data_size, vbuf->data_size);
+	}
+	inst->max_input_data_size = data_size;
+
+	frame_rate = msm_vidc_get_frame_rate(inst);
+	operating_rate = msm_vidc_get_operating_rate(inst);
+	fps = max(frame_rate, operating_rate);
+	/*
+	 * Consider input queuing rate in power scaling in
+	 * because client may not set the frame rate / operating rate
+	 * and we need to rely on input queue rate
+	 */
+	if (is_decode_session(inst)) {
+		/*
+		 * when buffer detected fps is more than client set value by 12.5%,
+		 * utilize buffer detected fps to scale clock.
+		 */
+		timestamp_rate = msm_vidc_get_timestamp_rate(inst);
+		input_rate = msm_vidc_get_input_rate(inst);
+		if (timestamp_rate > (fps + fps / 8))
+			fps = timestamp_rate;
+
+		if (input_rate > fps)
+			fps = input_rate;
+	}
+	inst->max_rate = fps;
+
+	/* no pending inputs - skip scale power */
+	if (!inst->max_input_data_size)
+		return 0;
+
+	if (msm_vidc_scale_clocks(inst))
+		i_vpr_e(inst, "failed to scale clock\n");
+
+	if (scale_buses) {
+		if (msm_vidc_scale_buses(inst))
+			i_vpr_e(inst, "failed to scale bus\n");
+	}
+
+	i_vpr_hp(inst,
+		 "power: inst: clk %lld ddr %d llcc %d dcvs flags %#x fps %u (%u %u %u %u) core: clk %lld ddr %lld llcc %lld\n",
+		 inst->power.curr_freq, inst->power.ddr_bw,
+		 inst->power.sys_cache_bw, inst->power.dcvs_flags,
+		 inst->max_rate, frame_rate, operating_rate, timestamp_rate,
+		 input_rate, core->power.clk_freq, core->power.bw_ddr,
+		 core->power.bw_llcc);
+
+	return 0;
+}
+
+void msm_vidc_dcvs_data_reset(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_power *dcvs;
+	u32 min_count, actual_count, max_count;
+
+	dcvs = &inst->power;
+	if (is_encode_session(inst)) {
+		min_count = inst->buffers.input.min_count;
+		actual_count = inst->buffers.input.actual_count;
+		max_count = min((min_count + DCVS_ENC_EXTRA_INPUT_BUFFERS), actual_count);
+	} else if (is_decode_session(inst)) {
+		min_count = inst->buffers.output.min_count;
+		actual_count = inst->buffers.output.actual_count;
+		max_count = min((min_count + DCVS_DEC_EXTRA_OUTPUT_BUFFERS), actual_count);
+	} else {
+		i_vpr_e(inst, "%s: invalid domain type %d\n",
+			__func__, inst->domain);
+		return;
+	}
+
+	dcvs->min_threshold = min_count;
+	dcvs->max_threshold = max_count;
+	dcvs->dcvs_window = min_count < max_count ? max_count - min_count : 0;
+	dcvs->nom_threshold = dcvs->min_threshold + (dcvs->dcvs_window / 2);
+	dcvs->dcvs_flags = 0;
+
+	i_vpr_p(inst, "%s: dcvs: thresholds [%d %d %d] flags %#x\n",
+		__func__, dcvs->min_threshold,
+		dcvs->nom_threshold, dcvs->max_threshold,
+		dcvs->dcvs_flags);
+}
+
+void msm_vidc_power_data_reset(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	msm_vidc_dcvs_data_reset(inst);
+
+	inst->power.buffer_counter = 0;
+	inst->power.fw_cr = 0;
+	inst->power.fw_cf = INT_MAX;
+
+	rc = msm_vidc_scale_power(inst, true);
+	if (rc)
+		i_vpr_e(inst, "%s: failed to scale power\n", __func__);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 14/33] iris: vidc: add helpers for state management
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (12 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 13/33] iris: vidc: add helper functions for power management Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:52   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 15/33] iris: add vidc buffer files Vikash Garodia
                   ` (21 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements the functions to handle different core
and instance state transitions.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_state.h   |  102 ++
 .../platform/qcom/iris/vidc/src/msm_vidc_state.c   | 1607 ++++++++++++++++++++
 2 files changed, 1709 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
new file mode 100644
index 0000000..7fe4fcc
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_STATE_H_
+#define _MSM_VIDC_STATE_H_
+
+#include "msm_vidc_internal.h"
+
+enum msm_vidc_core_state {
+	MSM_VIDC_CORE_DEINIT,
+	MSM_VIDC_CORE_INIT_WAIT,
+	MSM_VIDC_CORE_INIT,
+	MSM_VIDC_CORE_ERROR,
+};
+
+enum msm_vidc_core_sub_state {
+	CORE_SUBSTATE_NONE                   = 0x0,
+	CORE_SUBSTATE_POWER_ENABLE           = BIT(0),
+	CORE_SUBSTATE_GDSC_HANDOFF           = BIT(1),
+	CORE_SUBSTATE_PM_SUSPEND             = BIT(2),
+	CORE_SUBSTATE_FW_PWR_CTRL            = BIT(3),
+	CORE_SUBSTATE_PAGE_FAULT             = BIT(4),
+	CORE_SUBSTATE_CPU_WATCHDOG           = BIT(5),
+	CORE_SUBSTATE_VIDEO_UNRESPONSIVE     = BIT(6),
+	CORE_SUBSTATE_MAX                    = BIT(7),
+};
+
+enum msm_vidc_core_event_type {
+	CORE_EVENT_NONE                      = BIT(0),
+	CORE_EVENT_UPDATE_SUB_STATE          = BIT(1),
+};
+
+enum msm_vidc_state {
+	MSM_VIDC_OPEN,
+	MSM_VIDC_INPUT_STREAMING,
+	MSM_VIDC_OUTPUT_STREAMING,
+	MSM_VIDC_STREAMING,
+	MSM_VIDC_CLOSE,
+	MSM_VIDC_ERROR,
+};
+
+#define MSM_VIDC_SUB_STATE_NONE          0
+#define MSM_VIDC_MAX_SUB_STATES          6
+/*
+ * max value of inst->sub_state if all
+ * the 6 valid bits are set i.e 111111==>63
+ */
+#define MSM_VIDC_MAX_SUB_STATE_VALUE     ((1 << MSM_VIDC_MAX_SUB_STATES) - 1)
+
+enum msm_vidc_sub_state {
+	MSM_VIDC_DRAIN                     = BIT(0),
+	MSM_VIDC_DRC                       = BIT(1),
+	MSM_VIDC_DRAIN_LAST_BUFFER         = BIT(2),
+	MSM_VIDC_DRC_LAST_BUFFER           = BIT(3),
+	MSM_VIDC_INPUT_PAUSE               = BIT(4),
+	MSM_VIDC_OUTPUT_PAUSE              = BIT(5),
+};
+
+enum msm_vidc_event {
+	MSM_VIDC_TRY_FMT,
+	MSM_VIDC_S_FMT,
+	MSM_VIDC_REQBUFS,
+	MSM_VIDC_S_CTRL,
+	MSM_VIDC_STREAMON,
+	MSM_VIDC_STREAMOFF,
+	MSM_VIDC_CMD_START,
+	MSM_VIDC_CMD_STOP,
+	MSM_VIDC_BUF_QUEUE,
+};
+
+/* core statemachine functions */
+enum msm_vidc_allow msm_vidc_allow_core_state_change(struct msm_vidc_core *core,
+						     enum msm_vidc_core_state req_state);
+int msm_vidc_update_core_state(struct msm_vidc_core *core,
+			       enum msm_vidc_core_state request_state, const char *func);
+bool core_in_valid_state(struct msm_vidc_core *core);
+bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state);
+bool is_core_sub_state(struct msm_vidc_core *core, enum msm_vidc_core_sub_state sub_state);
+const char *core_state_name(enum msm_vidc_core_state state);
+const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state);
+
+/* inst statemachine functions */
+bool is_drc_pending(struct msm_vidc_inst *inst);
+bool is_drain_pending(struct msm_vidc_inst *inst);
+int msm_vidc_update_state(struct msm_vidc_inst *inst,
+			  enum msm_vidc_state request_state, const char *func);
+int msm_vidc_change_state(struct msm_vidc_inst *inst,
+			  enum msm_vidc_state request_state, const char *func);
+int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
+			      enum msm_vidc_sub_state clear_sub_state,
+			      enum msm_vidc_sub_state set_sub_state,
+			      const char *func);
+const char *state_name(enum msm_vidc_state state);
+const char *sub_state_name(enum msm_vidc_sub_state sub_state);
+bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state);
+bool is_sub_state(struct msm_vidc_inst *inst,
+		  enum msm_vidc_sub_state sub_state);
+
+#endif // _MSM_VIDC_STATE_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
new file mode 100644
index 0000000..0361e69
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
@@ -0,0 +1,1607 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_state.h"
+#include "msm_vidc_vb2.h"
+#include "venus_hfi.h"
+
+bool core_in_valid_state(struct msm_vidc_core *core)
+{
+	return (core->state == MSM_VIDC_CORE_INIT ||
+		core->state == MSM_VIDC_CORE_INIT_WAIT);
+}
+
+bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state)
+{
+	return core->state == state;
+}
+
+bool is_drc_pending(struct msm_vidc_inst *inst)
+{
+	return is_sub_state(inst, MSM_VIDC_DRC) &&
+		is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER);
+}
+
+bool is_drain_pending(struct msm_vidc_inst *inst)
+{
+	return is_sub_state(inst, MSM_VIDC_DRAIN) &&
+		is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER);
+}
+
+static const char * const core_state_name_arr[] = {
+	[MSM_VIDC_CORE_DEINIT] =    "CORE_DEINIT",
+	[MSM_VIDC_CORE_INIT_WAIT] = "CORE_INIT_WAIT",
+	[MSM_VIDC_CORE_INIT] =      "CORE_INIT",
+	[MSM_VIDC_CORE_ERROR] =     "CORE_ERROR",
+};
+
+const char *core_state_name(enum msm_vidc_core_state state)
+{
+	const char *name = "UNKNOWN STATE";
+
+	if (state >= ARRAY_SIZE(core_state_name_arr))
+		goto exit;
+
+	name = core_state_name_arr[state];
+
+exit:
+	return name;
+}
+
+static const char * const event_name_arr[] = {
+	[MSM_VIDC_TRY_FMT] =   "TRY_FMT",
+	[MSM_VIDC_S_FMT] =     "S_FMT",
+	[MSM_VIDC_REQBUFS] =   "REQBUFS",
+	[MSM_VIDC_S_CTRL] =    "S_CTRL",
+	[MSM_VIDC_STREAMON] =  "STREAMON",
+	[MSM_VIDC_STREAMOFF] = "STREAMOFF",
+	[MSM_VIDC_CMD_START] = "CMD_START",
+	[MSM_VIDC_CMD_STOP] =  "CMD_STOP",
+	[MSM_VIDC_BUF_QUEUE] = "BUF_QUEUE",
+};
+
+static const char *event_name(enum msm_vidc_event event)
+{
+	const char *name = "UNKNOWN EVENT";
+
+	if (event >= ARRAY_SIZE(event_name_arr))
+		goto exit;
+
+	name = event_name_arr[event];
+
+exit:
+	return name;
+}
+
+static int __strict_inst_check(struct msm_vidc_inst *inst, const char *function)
+{
+	bool fatal = !mutex_is_locked(&inst->lock);
+
+	WARN_ON(fatal);
+
+	return fatal ? -EINVAL : 0;
+}
+
+struct msm_vidc_core_sub_state_allow {
+	enum msm_vidc_core_state       state;
+	enum msm_vidc_allow            allow;
+	u32                            sub_state_mask;
+};
+
+static u32 msm_vidc_core_sub_state_mask(enum msm_vidc_core_state state,
+					u32 allow)
+{
+	int cnt;
+	u32 sub_state_mask = 0;
+	static struct msm_vidc_core_sub_state_allow sub_state[] = {
+		/* state, allow, sub_state */
+		{MSM_VIDC_CORE_DEINIT,    MSM_VIDC_ALLOW,       CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_DEINIT,     MSM_VIDC_IGNORE,     CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_INIT_WAIT,  MSM_VIDC_ALLOW,      CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_INIT_WAIT,  MSM_VIDC_DISALLOW,   CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_INIT_WAIT,  MSM_VIDC_IGNORE,     CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_INIT,       MSM_VIDC_ALLOW,      CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_ERROR,      MSM_VIDC_ALLOW,      CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+		{MSM_VIDC_CORE_ERROR,      MSM_VIDC_DISALLOW,   CORE_SUBSTATE_POWER_ENABLE       |
+								CORE_SUBSTATE_GDSC_HANDOFF       |
+								CORE_SUBSTATE_PM_SUSPEND         |
+								CORE_SUBSTATE_FW_PWR_CTRL        |
+								CORE_SUBSTATE_PAGE_FAULT         |
+								CORE_SUBSTATE_CPU_WATCHDOG       |
+								CORE_SUBSTATE_VIDEO_UNRESPONSIVE },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(sub_state); cnt++) {
+		if (sub_state[cnt].state == state && sub_state[cnt].allow == allow) {
+			sub_state_mask = sub_state[cnt].sub_state_mask;
+			break;
+		}
+	}
+
+	return sub_state_mask;
+}
+
+static int msm_vidc_core_deinit_state(struct msm_vidc_core *core,
+				      enum msm_vidc_core_event_type type,
+				      struct msm_vidc_event_data *data)
+{
+	int rc = 0;
+
+	switch (type) {
+	case CORE_EVENT_UPDATE_SUB_STATE:
+	{
+		u32 req_sub_state = data->edata.uval;
+		u32 allow_mask = msm_vidc_core_sub_state_mask(core->state, MSM_VIDC_ALLOW);
+
+		req_sub_state = data->edata.uval;
+
+		/* none of the requested substate supported */
+		if (!(req_sub_state & allow_mask)) {
+			d_vpr_e("%s: invalid substate update request %#x\n",
+				__func__, req_sub_state);
+			return -EINVAL;
+		}
+
+		/* update core substate */
+		core->sub_state |= req_sub_state & allow_mask;
+		return rc;
+	}
+	default: {
+		d_vpr_e("%s: unexpected core event type %u\n",
+			__func__, type);
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_core_init_wait_state(struct msm_vidc_core *core,
+					 enum msm_vidc_core_event_type type,
+					 struct msm_vidc_event_data *data)
+{
+	int rc = 0;
+
+	switch (type) {
+	case CORE_EVENT_UPDATE_SUB_STATE:
+	{
+		u32 req_sub_state = data->edata.uval;
+		u32 allow_mask = msm_vidc_core_sub_state_mask(core->state, MSM_VIDC_ALLOW);
+
+		req_sub_state = data->edata.uval;
+
+		/* none of the requested substate supported */
+		if (!(req_sub_state & allow_mask)) {
+			d_vpr_e("%s: invalid substate update request %#x\n",
+				__func__, req_sub_state);
+			return -EINVAL;
+		}
+
+		/* update core substate */
+		core->sub_state |= req_sub_state & allow_mask;
+		return rc;
+	}
+	default: {
+		d_vpr_e("%s: unexpected core event type %u\n",
+			__func__, type);
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_core_init_state(struct msm_vidc_core *core,
+				    enum msm_vidc_core_event_type type,
+				    struct msm_vidc_event_data *data)
+{
+	int rc = 0;
+
+	switch (type) {
+	case CORE_EVENT_UPDATE_SUB_STATE:
+	{
+		u32 req_sub_state = data->edata.uval;
+		u32 allow_mask = msm_vidc_core_sub_state_mask(core->state, MSM_VIDC_ALLOW);
+
+		req_sub_state = data->edata.uval;
+
+		/* none of the requested substate supported */
+		if (!(req_sub_state & allow_mask)) {
+			d_vpr_e("%s: invalid substate update request %#x\n",
+				__func__, req_sub_state);
+			return -EINVAL;
+		}
+
+		/* update core substate */
+		core->sub_state |= req_sub_state & allow_mask;
+		return rc;
+	}
+	default: {
+		d_vpr_e("%s: unexpected core event type %u\n",
+			__func__, type);
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_core_error_state(struct msm_vidc_core *core,
+				     enum msm_vidc_core_event_type type,
+				     struct msm_vidc_event_data *data)
+{
+	int rc = 0;
+
+	switch (type) {
+	case CORE_EVENT_UPDATE_SUB_STATE:
+	{
+		u32 req_sub_state = data->edata.uval;
+		u32 allow_mask = msm_vidc_core_sub_state_mask(core->state, MSM_VIDC_ALLOW);
+
+		req_sub_state = data->edata.uval;
+
+		/* none of the requested substate supported */
+		if (!(req_sub_state & allow_mask)) {
+			d_vpr_e("%s: invalid substate update request %#x\n",
+				__func__, req_sub_state);
+			return -EINVAL;
+		}
+
+		/* update core substate */
+		core->sub_state |= req_sub_state & allow_mask;
+		return rc;
+	}
+	default: {
+		d_vpr_e("%s: unexpected core event type %u\n",
+			__func__, type);
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+struct msm_vidc_core_state_handle {
+	enum msm_vidc_core_state   state;
+	int			 (*handle)(struct msm_vidc_core *core,
+					   enum msm_vidc_core_event_type type,
+					   struct msm_vidc_event_data *data);
+};
+
+static struct msm_vidc_core_state_handle
+	*msm_vidc_get_core_state_handle(enum msm_vidc_core_state req_state)
+{
+	int cnt;
+	struct msm_vidc_core_state_handle *core_state_handle = NULL;
+	static struct msm_vidc_core_state_handle state_handle[] = {
+		{MSM_VIDC_CORE_DEINIT,      msm_vidc_core_deinit_state      },
+		{MSM_VIDC_CORE_INIT_WAIT,   msm_vidc_core_init_wait_state   },
+		{MSM_VIDC_CORE_INIT,        msm_vidc_core_init_state        },
+		{MSM_VIDC_CORE_ERROR,       msm_vidc_core_error_state       },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) {
+		if (state_handle[cnt].state == req_state) {
+			core_state_handle = &state_handle[cnt];
+			break;
+		}
+	}
+
+	/* if req_state does not exist in the table */
+	if (cnt == ARRAY_SIZE(state_handle)) {
+		d_vpr_e("%s: invalid core state \"%s\" requested\n",
+			__func__, core_state_name(req_state));
+		return core_state_handle;
+	}
+
+	return core_state_handle;
+}
+
+int msm_vidc_update_core_state(struct msm_vidc_core *core,
+			       enum msm_vidc_core_state request_state, const char *func)
+{
+	struct msm_vidc_core_state_handle *state_handle = NULL;
+	int rc = 0;
+
+	/* get core state handler for requested state */
+	state_handle = msm_vidc_get_core_state_handle(request_state);
+	if (!state_handle)
+		return -EINVAL;
+
+	d_vpr_h("%s: core state changed to %s from %s\n", func,
+		core_state_name(state_handle->state), core_state_name(core->state));
+
+	/* finally update core state and handler */
+	core->state = state_handle->state;
+	core->state_handle = state_handle->handle;
+
+	return rc;
+}
+
+struct msm_vidc_core_state_allow {
+	enum msm_vidc_core_state   from;
+	enum msm_vidc_core_state   to;
+	enum msm_vidc_allow        allow;
+};
+
+enum msm_vidc_allow msm_vidc_allow_core_state_change(struct msm_vidc_core *core,
+						     enum msm_vidc_core_state req_state)
+{
+	int cnt;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	static struct msm_vidc_core_state_allow state[] = {
+		/* from, to, allow */
+		{MSM_VIDC_CORE_DEINIT,      MSM_VIDC_CORE_DEINIT,      MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_DEINIT,      MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_DEINIT,      MSM_VIDC_CORE_INIT,        MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CORE_DEINIT,      MSM_VIDC_CORE_ERROR,       MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_CORE_DEINIT,      MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_CORE_INIT,        MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_CORE_ERROR,       MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_INIT,        MSM_VIDC_CORE_DEINIT,      MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_INIT,        MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CORE_INIT,        MSM_VIDC_CORE_INIT,        MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_INIT,        MSM_VIDC_CORE_ERROR,       MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_ERROR,       MSM_VIDC_CORE_DEINIT,      MSM_VIDC_ALLOW     },
+		{MSM_VIDC_CORE_ERROR,       MSM_VIDC_CORE_INIT_WAIT,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_ERROR,       MSM_VIDC_CORE_INIT,        MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CORE_ERROR,       MSM_VIDC_CORE_ERROR,       MSM_VIDC_IGNORE    },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
+		if (state[cnt].from == core->state && state[cnt].to == req_state) {
+			allow = state[cnt].allow;
+			break;
+		}
+	}
+
+	return allow;
+}
+
+int msm_vidc_change_core_state(struct msm_vidc_core *core,
+			       enum msm_vidc_core_state request_state, const char *func)
+{
+	enum msm_vidc_allow allow;
+	int rc = 0;
+
+	/* core must be locked */
+	rc = __strict_check(core, func);
+	if (rc) {
+		d_vpr_e("%s(): core was not locked\n", func);
+		return rc;
+	}
+
+	/* current and requested state is same */
+	if (core->state == request_state)
+		return 0;
+
+	/* check if requested state movement is allowed */
+	allow = msm_vidc_allow_core_state_change(core, request_state);
+	if (allow == MSM_VIDC_IGNORE) {
+		d_vpr_h("%s: %s core state change %s -> %s\n", func,
+			allow_name(allow), core_state_name(core->state),
+			core_state_name(request_state));
+		return 0;
+	} else if (allow == MSM_VIDC_DISALLOW) {
+		d_vpr_e("%s: %s core state change %s -> %s\n", func,
+			allow_name(allow), core_state_name(core->state),
+			core_state_name(request_state));
+		return -EINVAL;
+	}
+
+	/* go ahead and update core state */
+	return msm_vidc_update_core_state(core, request_state, func);
+}
+
+bool is_core_sub_state(struct msm_vidc_core *core, enum msm_vidc_core_sub_state sub_state)
+{
+	return !!(core->sub_state & sub_state);
+}
+
+const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state)
+{
+	switch (sub_state) {
+	case CORE_SUBSTATE_NONE:                 return "NONE ";
+	case CORE_SUBSTATE_GDSC_HANDOFF:         return "GDSC_HANDOFF ";
+	case CORE_SUBSTATE_PM_SUSPEND:           return "PM_SUSPEND ";
+	case CORE_SUBSTATE_FW_PWR_CTRL:          return "FW_PWR_CTRL ";
+	case CORE_SUBSTATE_POWER_ENABLE:         return "POWER_ENABLE ";
+	case CORE_SUBSTATE_PAGE_FAULT:           return "PAGE_FAULT ";
+	case CORE_SUBSTATE_CPU_WATCHDOG:         return "CPU_WATCHDOG ";
+	case CORE_SUBSTATE_VIDEO_UNRESPONSIVE:   return "VIDEO_UNRESPONSIVE ";
+	case CORE_SUBSTATE_MAX:                  return "MAX ";
+	}
+
+	return "UNKNOWN ";
+}
+
+static int prepare_core_sub_state_name(enum msm_vidc_core_sub_state sub_state,
+				       char *buf, u32 size)
+{
+	int i = 0;
+
+	if (!buf || !size)
+		return -EINVAL;
+
+	strscpy(buf, "\0", size);
+	if (sub_state == CORE_SUBSTATE_NONE) {
+		strscpy(buf, "CORE_SUBSTATE_NONE", size);
+		return 0;
+	}
+
+	for (i = 0; BIT(i) < CORE_SUBSTATE_MAX; i++) {
+		if (sub_state & BIT(i))
+			strlcat(buf, core_sub_state_name(BIT(i)), size);
+	}
+
+	return 0;
+}
+
+static int msm_vidc_update_core_sub_state(struct msm_vidc_core *core,
+					  enum msm_vidc_core_sub_state sub_state,
+					  const char *func)
+{
+	struct msm_vidc_event_data data;
+	char sub_state_name[MAX_NAME_LENGTH];
+	int ret = 0, rc = 0;
+
+	/* no substate update */
+	if (!sub_state)
+		return 0;
+
+	/* invoke update core substate event */
+	memset(&data, 0, sizeof(struct msm_vidc_event_data));
+	data.edata.uval = sub_state;
+	rc = core->state_handle(core, CORE_EVENT_UPDATE_SUB_STATE, &data);
+	if (rc) {
+		ret = prepare_core_sub_state_name(sub_state, sub_state_name,
+						  sizeof(sub_state_name) - 1);
+		if (!ret)
+			d_vpr_e("%s: state %s, requested invalid core substate %s\n",
+				func, core_state_name(core->state), sub_state_name);
+		return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
+				   enum msm_vidc_core_sub_state clear_sub_state,
+				   enum msm_vidc_core_sub_state set_sub_state,
+				   const char *func)
+{
+	int rc = 0;
+	enum msm_vidc_core_sub_state prev_sub_state;
+
+	/* core must be locked */
+	rc = __strict_check(core, func);
+	if (rc) {
+		d_vpr_e("%s(): core was not locked\n", func);
+		return rc;
+	}
+
+	/* sanitize core state handler */
+	if (!core->state_handle) {
+		d_vpr_e("%s: invalid core state handle\n", __func__);
+		return -EINVAL;
+	}
+
+	/* final value will not change */
+	if (clear_sub_state == set_sub_state)
+		return 0;
+
+	/* sanitize clear & set value */
+	if (set_sub_state > CORE_SUBSTATE_MAX ||
+	    clear_sub_state > CORE_SUBSTATE_MAX) {
+		d_vpr_e("%s: invalid sub states. clear %#x or set %#x\n",
+			func, clear_sub_state, set_sub_state);
+		return -EINVAL;
+	}
+
+	prev_sub_state = core->sub_state;
+
+	/* set sub state */
+	rc = msm_vidc_update_core_sub_state(core, set_sub_state, func);
+	if (rc)
+		return rc;
+
+	/* check if all core substates updated */
+	if ((core->sub_state & set_sub_state) != set_sub_state)
+		d_vpr_e("%s: all substates not updated %#x, expected %#x\n",
+			func, core->sub_state & set_sub_state, set_sub_state);
+
+	/* clear sub state */
+	core->sub_state &= ~clear_sub_state;
+
+	/* print substates only when there is a change */
+	if (core->sub_state != prev_sub_state) {
+		rc = prepare_core_sub_state_name(core->sub_state, core->sub_state_name,
+						 sizeof(core->sub_state_name) - 1);
+		if (!rc)
+			d_vpr_h("%s: core sub state changed to %s\n", func, core->sub_state_name);
+	}
+
+	return 0;
+}
+
+/* do not modify the state names as it is used in test scripts */
+static const char * const state_name_arr[] = {
+	[MSM_VIDC_OPEN] =             "OPEN",
+	[MSM_VIDC_INPUT_STREAMING] =  "INPUT_STREAMING",
+	[MSM_VIDC_OUTPUT_STREAMING] = "OUTPUT_STREAMING",
+	[MSM_VIDC_STREAMING] =        "STREAMING",
+	[MSM_VIDC_CLOSE] =            "CLOSE",
+	[MSM_VIDC_ERROR] =            "ERROR",
+};
+
+const char *state_name(enum msm_vidc_state state)
+{
+	const char *name = "UNKNOWN STATE";
+
+	if (state >= ARRAY_SIZE(state_name_arr))
+		goto exit;
+
+	name = state_name_arr[state];
+
+exit:
+	return name;
+}
+
+bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state)
+{
+	return inst->state == state;
+}
+
+bool is_sub_state(struct msm_vidc_inst *inst, enum msm_vidc_sub_state sub_state)
+{
+	return (inst->sub_state & sub_state);
+}
+
+const char *sub_state_name(enum msm_vidc_sub_state sub_state)
+{
+	switch (sub_state) {
+	case MSM_VIDC_DRAIN:               return "DRAIN ";
+	case MSM_VIDC_DRC:                 return "DRC ";
+	case MSM_VIDC_DRAIN_LAST_BUFFER:   return "DRAIN_LAST_BUFFER ";
+	case MSM_VIDC_DRC_LAST_BUFFER:     return "DRC_LAST_BUFFER ";
+	case MSM_VIDC_INPUT_PAUSE:         return "INPUT_PAUSE ";
+	case MSM_VIDC_OUTPUT_PAUSE:        return "OUTPUT_PAUSE ";
+	}
+
+	return "SUB_STATE_NONE";
+}
+
+static int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
+				  char *buf, u32 size)
+{
+	int i = 0;
+
+	if (!buf || !size)
+		return -EINVAL;
+
+	strscpy(buf, "\0", size);
+	if (sub_state == MSM_VIDC_SUB_STATE_NONE) {
+		strscpy(buf, "SUB_STATE_NONE", size);
+		return 0;
+	}
+
+	for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) {
+		if (sub_state & BIT(i))
+			strlcat(buf, sub_state_name(BIT(i)), size);
+	}
+
+	return 0;
+}
+
+struct msm_vidc_state_allow {
+	enum msm_vidc_state        from;
+	enum msm_vidc_state        to;
+	enum msm_vidc_allow        allow;
+};
+
+static enum msm_vidc_allow msm_vidc_allow_state_change(struct msm_vidc_inst *inst,
+						       enum msm_vidc_state req_state)
+{
+	int cnt;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	static struct msm_vidc_state_allow state[] = {
+		/* from, to, allow */
+		{MSM_VIDC_OPEN,             MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OPEN,             MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OPEN,             MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_CLOSE,              MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+
+		{MSM_VIDC_ERROR,            MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_CLOSE,              MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
+		if (state[cnt].from == inst->state && state[cnt].to == req_state) {
+			allow = state[cnt].allow;
+			break;
+		}
+	}
+
+	return allow;
+}
+
+static int msm_vidc_open_state(struct msm_vidc_inst *inst,
+			       enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_TRY_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* allow try_fmt request in open state */
+		rc = msm_vidc_try_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* allow s_fmt request in open state */
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+
+		/* allow set_control request in open state */
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		/* allow reqbufs request in open state */
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* allow streamon request in open state */
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* ignore streamoff request in open state */
+		i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
+			__func__, v4l2_type_name(q->type), state_name(inst->state));
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		/* disallow start cmd request in open state */
+		i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
+			__func__, event_name(event), inst->sub_state_name);
+
+		return -EBUSY;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		/* ignore stop cmd request in open state */
+		i_vpr_h(inst, "%s: (%s) ignored, sub_state (%s)\n",
+			__func__, event_name(event), inst->sub_state_name);
+		break;
+	}
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer qbuf request in open state */
+		print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+		break;
+	}
+	default:
+	{
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst,
+					  enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* disallow */
+		if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer output port */
+		if (is_output_buffer(buf->type)) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_TRY_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* disallow */
+		if (f->type == INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(f->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_try_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* disallow */
+		if (f->type == INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(f->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (is_decode_session(inst)) {
+			/* check dynamic allowed if master port is streaming */
+			if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+				i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+					__func__, cap_id, state_name(inst->state));
+				return -EINVAL;
+			}
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		/* disallow */
+		if (b->type == INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(b->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* disallow */
+		if (q->type == INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n",
+				__func__, event_name(event), v4l2_type_name(q->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* ignore */
+		if (q->type == OUTPUT_MPLANE) {
+			i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
+				__func__, v4l2_type_name(q->type), state_name(inst->state));
+			return 0;
+		}
+
+		/* sanitize type field */
+		if (q->type != INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		/* disallow if START called for non DRC/drain cases */
+		if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
+			i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
+				__func__, event_name(event), inst->sub_state_name);
+			return -EBUSY;
+		}
+
+		/* client would call start(resume) to complete DRC/drain sequence */
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		/* back to back drain not allowed */
+		if (is_sub_state(inst, MSM_VIDC_DRAIN)) {
+			i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n",
+				__func__, event_name(event), inst->sub_state_name);
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	default:
+	{
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst,
+					   enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* disallow */
+		if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer input port */
+		if (is_input_buffer(buf->type)) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_TRY_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* disallow */
+		if (f->type == OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(f->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_try_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		/* disallow */
+		if (f->type == OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(f->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (is_encode_session(inst)) {
+			/* check dynamic allowed if master port is streaming */
+			if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+				i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+					__func__, cap_id, state_name(inst->state));
+				return -EINVAL;
+			}
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		/* disallow */
+		if (b->type == OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n",
+				__func__, event_name(event), v4l2_type_name(b->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* disallow */
+		if (q->type == OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n",
+				__func__, event_name(event), v4l2_type_name(q->type));
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* ignore */
+		if (q->type == INPUT_MPLANE) {
+			i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n",
+				__func__, v4l2_type_name(q->type), state_name(inst->state));
+			return 0;
+		}
+
+		/* sanitize type field */
+		if (q->type != OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		/* disallow if START called for non DRC/drain cases */
+		if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
+			i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
+				__func__, event_name(event), inst->sub_state_name);
+			return -EBUSY;
+		}
+
+		/* client would call start(resume) to complete DRC/drain sequence */
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		/* drain not allowed as input is not streaming */
+		i_vpr_e(inst, "%s: drain (%s) not allowed, sub state %s\n",
+			__func__, event_name(event), inst->sub_state_name);
+		return -EBUSY;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_streaming_state(struct msm_vidc_inst *inst,
+				    enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* disallow */
+		if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+			i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+				__func__, cap_id, state_name(inst->state));
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* sanitize type field */
+		if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		/* disallow if START called for non DRC/drain cases */
+		if (!is_drc_pending(inst) && !is_drain_pending(inst)) {
+			i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n",
+				__func__, event_name(event), inst->sub_state_name);
+			return -EBUSY;
+		}
+
+		/* client would call start(resume) to complete DRC/drain sequence */
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		/* back to back drain not allowed */
+		if (is_sub_state(inst, MSM_VIDC_DRAIN)) {
+			i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n",
+				__func__, event_name(event), inst->sub_state_name);
+			return -EBUSY;
+		}
+
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_close_state(struct msm_vidc_inst *inst,
+				enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_error_state(struct msm_vidc_inst *inst,
+				enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+struct msm_vidc_state_handle {
+	enum msm_vidc_state   state;
+	int                 (*handle)(struct msm_vidc_inst *inst,
+				      enum msm_vidc_event event, void *data);
+};
+
+static struct msm_vidc_state_handle *msm_vidc_get_state_handle(struct msm_vidc_inst *inst,
+							       enum msm_vidc_state req_state)
+{
+	int cnt;
+	struct msm_vidc_state_handle *inst_state_handle = NULL;
+	static struct msm_vidc_state_handle state_handle[] = {
+		{MSM_VIDC_OPEN,             msm_vidc_open_state             },
+		{MSM_VIDC_INPUT_STREAMING,  msm_vidc_input_streaming_state  },
+		{MSM_VIDC_OUTPUT_STREAMING, msm_vidc_output_streaming_state },
+		{MSM_VIDC_STREAMING,        msm_vidc_streaming_state        },
+		{MSM_VIDC_CLOSE,            msm_vidc_close_state            },
+		{MSM_VIDC_ERROR,            msm_vidc_error_state            },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) {
+		if (state_handle[cnt].state == req_state) {
+			inst_state_handle = &state_handle[cnt];
+			break;
+		}
+	}
+
+	/* check if req_state does not exist in the table */
+	if (cnt == ARRAY_SIZE(state_handle)) {
+		i_vpr_e(inst, "%s: invalid state %s\n", __func__, state_name(req_state));
+		return inst_state_handle;
+	}
+
+	return inst_state_handle;
+}
+
+int msm_vidc_update_state(struct msm_vidc_inst *inst,
+			  enum msm_vidc_state request_state, const char *func)
+{
+	struct msm_vidc_state_handle *state_handle = NULL;
+	int rc = 0;
+
+	/* get inst state handler for requested state */
+	state_handle = msm_vidc_get_state_handle(inst, request_state);
+	if (!state_handle)
+		return -EINVAL;
+
+	if (request_state == MSM_VIDC_ERROR)
+		i_vpr_e(inst, FMT_STRING_STATE_CHANGE,
+			func, state_name(request_state), state_name(inst->state));
+	else
+		i_vpr_h(inst, FMT_STRING_STATE_CHANGE,
+			func, state_name(request_state), state_name(inst->state));
+
+	/* finally update inst state and handler */
+	inst->state = state_handle->state;
+	inst->event_handle = state_handle->handle;
+
+	return rc;
+}
+
+int msm_vidc_change_state(struct msm_vidc_inst *inst,
+			  enum msm_vidc_state request_state, const char *func)
+{
+	enum msm_vidc_allow allow;
+	int rc;
+
+	if (is_session_error(inst)) {
+		i_vpr_h(inst,
+			"%s: inst is in bad state, can not change state to %s\n",
+			func, state_name(request_state));
+		return 0;
+	}
+
+	/* current and requested state is same */
+	if (inst->state == request_state)
+		return 0;
+
+	/* check if requested state movement is allowed */
+	allow = msm_vidc_allow_state_change(inst, request_state);
+	if (allow != MSM_VIDC_ALLOW) {
+		i_vpr_e(inst, "%s: %s state change %s -> %s\n", func,
+			allow_name(allow), state_name(inst->state),
+			state_name(request_state));
+		return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
+	}
+
+	/* go ahead and update inst state */
+	rc = msm_vidc_update_state(inst, request_state, func);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+struct msm_vidc_sub_state_allow {
+	enum msm_vidc_state            state;
+	enum msm_vidc_allow            allow;
+	u32                            sub_state_mask;
+};
+
+static int msm_vidc_set_sub_state(struct msm_vidc_inst *inst,
+				  enum msm_vidc_sub_state sub_state, const char *func)
+{
+	char sub_state_name[MAX_NAME_LENGTH];
+	int cnt, rc = 0;
+	static struct msm_vidc_sub_state_allow sub_state_allow[] = {
+		/* state, allow, sub_state */
+		{MSM_VIDC_OPEN,              MSM_VIDC_DISALLOW,    MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_INPUT_PAUSE         |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+
+		{MSM_VIDC_INPUT_STREAMING,   MSM_VIDC_DISALLOW,    MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+		{MSM_VIDC_INPUT_STREAMING,   MSM_VIDC_ALLOW,       MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_INPUT_PAUSE          },
+
+		{MSM_VIDC_OUTPUT_STREAMING,  MSM_VIDC_DISALLOW,    MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_INPUT_PAUSE          },
+		{MSM_VIDC_OUTPUT_STREAMING,  MSM_VIDC_ALLOW,       MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+
+		{MSM_VIDC_STREAMING,         MSM_VIDC_ALLOW,       MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_INPUT_PAUSE         |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+
+		{MSM_VIDC_CLOSE,             MSM_VIDC_ALLOW,       MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_INPUT_PAUSE         |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+
+		{MSM_VIDC_ERROR,             MSM_VIDC_ALLOW,       MSM_VIDC_DRC                 |
+								   MSM_VIDC_DRAIN               |
+								   MSM_VIDC_DRC_LAST_BUFFER     |
+								   MSM_VIDC_DRAIN_LAST_BUFFER   |
+								   MSM_VIDC_INPUT_PAUSE         |
+								   MSM_VIDC_OUTPUT_PAUSE         },
+	};
+
+	/* no substate to update */
+	if (!sub_state)
+		return 0;
+
+	/* check if any substate is disallowed */
+	for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
+		/* skip other states */
+		if (sub_state_allow[cnt].state != inst->state)
+			continue;
+
+		/* continue if not disallowed */
+		if (sub_state_allow[cnt].allow != MSM_VIDC_DISALLOW)
+			continue;
+
+		if (sub_state_allow[cnt].sub_state_mask & sub_state) {
+			prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
+			i_vpr_e(inst, "%s: state (%s), disallow substate (%s)\n",
+				func, state_name(inst->state), sub_state_name);
+			return -EINVAL;
+		}
+	}
+
+	/* remove ignorable substates from a given substate */
+	for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
+		/* skip other states */
+		if (sub_state_allow[cnt].state != inst->state)
+			continue;
+
+		/* continue if not ignored */
+		if (sub_state_allow[cnt].allow != MSM_VIDC_IGNORE)
+			continue;
+
+		if (sub_state_allow[cnt].sub_state_mask & sub_state) {
+			prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
+			i_vpr_h(inst, "%s: state (%s), ignore substate (%s)\n",
+				func, state_name(inst->state), sub_state_name);
+
+			/* remove ignorable substate bits from actual */
+			sub_state &= ~(sub_state_allow[cnt].sub_state_mask & sub_state);
+			break;
+		}
+	}
+
+	/* check if all substate bits are allowed */
+	for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) {
+		/* skip other states */
+		if (sub_state_allow[cnt].state != inst->state)
+			continue;
+
+		/* continue if not allowed */
+		if (sub_state_allow[cnt].allow != MSM_VIDC_ALLOW)
+			continue;
+
+		if ((sub_state_allow[cnt].sub_state_mask & sub_state) != sub_state) {
+			prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name));
+			i_vpr_e(inst, "%s: state (%s), not all substates allowed (%s)\n",
+				func, state_name(inst->state), sub_state_name);
+			return -EINVAL;
+		}
+	}
+
+	/* update substate */
+	inst->sub_state |= sub_state;
+
+	return rc;
+}
+
+int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
+			      enum msm_vidc_sub_state clear_sub_state,
+			      enum msm_vidc_sub_state set_sub_state, const char *func)
+{
+	enum msm_vidc_sub_state prev_sub_state;
+	int rc = 0;
+
+	if (is_session_error(inst)) {
+		i_vpr_h(inst,
+			"%s: inst is in bad state, can not change sub state\n", func);
+		return 0;
+	}
+
+	/* final value will not change */
+	if (!clear_sub_state && !set_sub_state)
+		return 0;
+
+	/* sanitize clear & set value */
+	if ((clear_sub_state & set_sub_state) ||
+	    set_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE ||
+	    clear_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE) {
+		i_vpr_e(inst, "%s: invalid sub states to clear %#x or set %#x\n",
+			func, clear_sub_state, set_sub_state);
+		return -EINVAL;
+	}
+
+	prev_sub_state = inst->sub_state;
+
+	/* set sub state */
+	rc = msm_vidc_set_sub_state(inst, set_sub_state, __func__);
+	if (rc)
+		return rc;
+
+	/* clear sub state */
+	inst->sub_state &= ~clear_sub_state;
+
+	/* print substates only when there is a change */
+	if (inst->sub_state != prev_sub_state) {
+		rc = prepare_sub_state_name(inst->sub_state, inst->sub_state_name,
+					    sizeof(inst->sub_state_name));
+		if (!rc)
+			i_vpr_h(inst, "%s: state %s and sub state changed to %s\n",
+				func, state_name(inst->state), inst->sub_state_name);
+	}
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 15/33] iris: add vidc buffer files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (13 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 14/33] iris: vidc: add helpers for state management Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 16/33] iris: add helpers for media format Vikash Garodia
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements the size and count calcualtions of
different types of buffers for encoder and decoder.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_buffer.h  |  32 +++
 .../platform/qcom/iris/vidc/src/msm_vidc_buffer.c  | 290 +++++++++++++++++++++
 2 files changed, 322 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
new file mode 100644
index 0000000..0fffcf0
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __H_MSM_VIDC_BUFFER_H__
+#define __H_MSM_VIDC_BUFFER_H__
+
+#include "msm_vidc_inst.h"
+
+#define MIN_DEC_INPUT_BUFFERS  4
+#define MIN_DEC_OUTPUT_BUFFERS 4
+
+#define MIN_ENC_INPUT_BUFFERS  4
+#define MIN_ENC_OUTPUT_BUFFERS 4
+
+#define DCVS_ENC_EXTRA_INPUT_BUFFERS  4
+#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
+
+u32 msm_vidc_input_min_count(struct msm_vidc_inst *inst);
+u32 msm_vidc_output_min_count(struct msm_vidc_inst *inst);
+u32 msm_vidc_input_extra_count(struct msm_vidc_inst *inst);
+u32 msm_vidc_output_extra_count(struct msm_vidc_inst *inst);
+u32 msm_vidc_internal_buffer_count(struct msm_vidc_inst *inst,
+				   enum msm_vidc_buffer_type buffer_type);
+u32 msm_vidc_decoder_input_size(struct msm_vidc_inst *inst);
+u32 msm_vidc_decoder_output_size(struct msm_vidc_inst *inst);
+u32 msm_vidc_encoder_input_size(struct msm_vidc_inst *inst);
+u32 msm_vidc_encoder_output_size(struct msm_vidc_inst *inst);
+
+#endif // __H_MSM_VIDC_BUFFER_H__
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
new file mode 100644
index 0000000..a2a0eea
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_media_info.h"
+#include "msm_vidc_buffer.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+/* Generic function for all targets. Not being used for iris2 */
+u32 msm_vidc_input_min_count(struct msm_vidc_inst *inst)
+{
+	u32 input_min_count = 0;
+	u32 hb_enh_layer = 0;
+
+	if (is_decode_session(inst)) {
+		input_min_count = MIN_DEC_INPUT_BUFFERS;
+	} else if (is_encode_session(inst)) {
+		input_min_count = MIN_ENC_INPUT_BUFFERS;
+		if (is_hierb_type_requested(inst)) {
+			hb_enh_layer =
+				inst->capabilities[ENH_LAYER_COUNT].value;
+			if (inst->codec == MSM_VIDC_H264 &&
+			    !inst->capabilities[LAYER_ENABLE].value) {
+				hb_enh_layer = 0;
+			}
+			if (hb_enh_layer)
+				input_min_count = (1 << hb_enh_layer) + 2;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %d\n",
+			__func__, inst->domain);
+		return 0;
+	}
+
+	return input_min_count;
+}
+
+u32 msm_vidc_output_min_count(struct msm_vidc_inst *inst)
+{
+	u32 output_min_count;
+
+	if (!is_decode_session(inst) && !is_encode_session(inst))
+		return 0;
+
+	if (is_encode_session(inst))
+		return MIN_ENC_OUTPUT_BUFFERS;
+
+	/* decoder handling below */
+	/* fw_min_count > 0 indicates reconfig event has already arrived */
+	if (inst->fw_min_count) {
+		if (is_split_mode_enabled(inst) &&
+		    inst->codec == MSM_VIDC_VP9) {
+			/*
+			 * return opb min buffer count as min(4, fw_min_count)
+			 * fw min count is used for dpb min count
+			 */
+			return min_t(u32, 4, inst->fw_min_count);
+		} else {
+			return inst->fw_min_count;
+		}
+	}
+
+	/* initial handling before reconfig event arrived */
+	switch (inst->codec) {
+	case MSM_VIDC_H264:
+	case MSM_VIDC_HEVC:
+		output_min_count = 4;
+		break;
+	case MSM_VIDC_VP9:
+		output_min_count = 9;
+		break;
+	default:
+		output_min_count = 4;
+		break;
+	}
+
+	return output_min_count;
+}
+
+u32 msm_vidc_input_extra_count(struct msm_vidc_inst *inst)
+{
+	u32 count = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (is_decode_session(inst)) {
+		/*
+		 * if decode batching enabled, ensure minimum batch size
+		 * count of input buffers present on input port
+		 */
+		if (core->capabilities[DECODE_BATCH].value &&
+		    inst->decode_batch.enable) {
+			if (inst->buffers.input.min_count < inst->decode_batch.size) {
+				count = inst->decode_batch.size -
+					inst->buffers.input.min_count;
+			}
+		}
+	} else if (is_encode_session(inst)) {
+		/* add dcvs buffers, if platform supports dcvs */
+		if (core->capabilities[DCVS].value)
+			count = DCVS_ENC_EXTRA_INPUT_BUFFERS;
+	}
+
+	return count;
+}
+
+u32 msm_vidc_output_extra_count(struct msm_vidc_inst *inst)
+{
+	u32 count = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (is_decode_session(inst)) {
+		/* add dcvs buffers, if platform supports dcvs */
+		if (core->capabilities[DCVS].value)
+			count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+		/*
+		 * if decode batching enabled, ensure minimum batch size
+		 * count of extra output buffers added on output port
+		 */
+		if (core->capabilities[DECODE_BATCH].value &&
+		    inst->decode_batch.enable &&
+			count < inst->decode_batch.size)
+			count = inst->decode_batch.size;
+	}
+
+	return count;
+}
+
+u32 msm_vidc_internal_buffer_count(struct msm_vidc_inst *inst,
+				   enum msm_vidc_buffer_type buffer_type)
+{
+	u32 count = 0;
+
+	if (is_encode_session(inst))
+		return 1;
+
+	if (is_decode_session(inst)) {
+		if (buffer_type == MSM_VIDC_BUF_BIN ||
+		    buffer_type == MSM_VIDC_BUF_LINE ||
+		    buffer_type == MSM_VIDC_BUF_PERSIST) {
+			count = 1;
+		} else if (buffer_type == MSM_VIDC_BUF_COMV ||
+			buffer_type == MSM_VIDC_BUF_NON_COMV) {
+			if (inst->codec == MSM_VIDC_H264 ||
+			    inst->codec == MSM_VIDC_HEVC)
+				count = 1;
+			else
+				count = 0;
+		} else {
+			i_vpr_e(inst, "%s: unsupported buffer type %s\n",
+				__func__, buf_name(buffer_type));
+			count = 0;
+		}
+	}
+
+	return count;
+}
+
+u32 msm_vidc_decoder_input_size(struct msm_vidc_inst *inst)
+{
+	u32 frame_size, num_mbs;
+	u32 div_factor = 1;
+	u32 base_res_mbs = NUM_MBS_4k;
+	struct v4l2_format *f;
+	u32 bitstream_size_overwrite = 0;
+	enum msm_vidc_codec_type codec;
+
+	bitstream_size_overwrite =
+		inst->capabilities[BITSTREAM_SIZE_OVERWRITE].value;
+	if (bitstream_size_overwrite) {
+		frame_size = bitstream_size_overwrite;
+		i_vpr_h(inst, "client configured bitstream buffer size %d\n",
+			frame_size);
+		return frame_size;
+	}
+
+	/*
+	 * Decoder input size calculation:
+	 * For 8k resolution, buffer size is calculated as 8k mbs / 4 and
+	 * for 8k cases we expect width/height to be set always.
+	 * In all other cases, buffer size is calculated as
+	 * 4k mbs for VP8/VP9 and 4k / 2 for remaining codecs.
+	 */
+	f = &inst->fmts[INPUT_PORT];
+	codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+	num_mbs = msm_vidc_get_mbs_per_frame(inst);
+	if (num_mbs > NUM_MBS_4k) {
+		div_factor = 4;
+		base_res_mbs = inst->capabilities[MBPF].value;
+	} else {
+		base_res_mbs = NUM_MBS_4k;
+		if (codec == MSM_VIDC_VP9)
+			div_factor = 1;
+		else
+			div_factor = 2;
+	}
+
+	frame_size = base_res_mbs * MB_SIZE_IN_PIXEL * 3 / 2 / div_factor;
+
+	 /* multiply by 10/8 (1.25) to get size for 10 bit case */
+	if (codec == MSM_VIDC_VP9 || codec == MSM_VIDC_HEVC)
+		frame_size = frame_size + (frame_size >> 2);
+
+	i_vpr_h(inst, "set input buffer size to %d\n", frame_size);
+
+	return ALIGN(frame_size, SZ_4K);
+}
+
+u32 msm_vidc_decoder_output_size(struct msm_vidc_inst *inst)
+{
+	u32 size;
+	struct v4l2_format *f;
+	enum msm_vidc_colorformat_type colorformat;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat,
+						 __func__);
+	size = video_buffer_size(colorformat, f->fmt.pix_mp.width,
+				 f->fmt.pix_mp.height, true);
+	return size;
+}
+
+u32 msm_vidc_encoder_input_size(struct msm_vidc_inst *inst)
+{
+	u32 size;
+	struct v4l2_format *f;
+	u32 width, height;
+	enum msm_vidc_colorformat_type colorformat;
+
+	f = &inst->fmts[INPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+	colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat,
+						 __func__);
+	size = video_buffer_size(colorformat, width, height, true);
+	return size;
+}
+
+u32 msm_vidc_encoder_output_size(struct msm_vidc_inst *inst)
+{
+	u32 frame_size;
+	u32 mbs_per_frame;
+	u32 width, height;
+	struct v4l2_format *f;
+	enum msm_vidc_codec_type codec;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+	/*
+	 * Encoder output size calculation: 32 Align width/height
+	 * For resolution <= 480x360p : YUVsize * 2
+	 * For resolution > 360p & <= 4K : YUVsize / 2
+	 * For resolution > 4k : YUVsize / 4
+	 * Initially frame_size = YUVsize * 2;
+	 */
+
+	width = ALIGN(f->fmt.pix_mp.width, BUFFER_ALIGNMENT_SIZE(32));
+	height = ALIGN(f->fmt.pix_mp.height, BUFFER_ALIGNMENT_SIZE(32));
+	mbs_per_frame = NUM_MBS_PER_FRAME(width, height);
+	frame_size = (width * height * 3);
+
+	/* Image session: 2 x yuv size */
+	if (inst->capabilities[BITRATE_MODE].value == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+		goto skip_calc;
+
+	if (mbs_per_frame <= NUM_MBS_360P)
+		(void)frame_size; /* Default frame_size = YUVsize * 2 */
+	else if (mbs_per_frame <= NUM_MBS_4k)
+		frame_size = frame_size >> 2;
+	else
+		frame_size = frame_size >> 3;
+
+skip_calc:
+	/* multiply by 10/8 (1.25) to get size for 10 bit case */
+	if (codec == MSM_VIDC_HEVC)
+		frame_size = frame_size + (frame_size >> 2);
+
+	frame_size = ALIGN(frame_size, SZ_4K);
+
+	return frame_size;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 16/33] iris: add helpers for media format
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (14 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 15/33] iris: add vidc buffer files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:55   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 17/33] iris: vidc: define various structures and enum Vikash Garodia
                   ` (19 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

Add helpers to calculate stride, scanline, buffer size
etc. for different media formats.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_media_info.h   | 599 +++++++++++++++++++++
 1 file changed, 599 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
new file mode 100644
index 0000000..772b2482
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
@@ -0,0 +1,599 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MSM_MEDIA_INFO_H__
+#define __MSM_MEDIA_INFO_H__
+
+#include "msm_vidc_internal.h"
+
+/* Width and Height should be multiple of 16 */
+#define INTERLACE_WIDTH_MAX 1920
+#define INTERLACE_HEIGHT_MAX 1920
+#define INTERLACE_MB_PER_FRAME_MAX ((1920 * 1088) / 256)
+
+#ifndef MSM_MEDIA_ALIGN
+#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\
+	((((__sz) + (__align) - 1) / (__align)) * (__align)) :\
+	(((__sz) + (__align) - 1) & (~((__align) - 1))))
+#endif
+
+#ifndef MSM_MEDIA_ROUNDUP
+#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r))
+#endif
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_y_stride_bytes(unsigned int colorformat,
+						unsigned int width)
+{
+	unsigned int alignment, stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12C:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		alignment = 256;
+		stride = MSM_MEDIA_ALIGN(width, 192);
+		stride = MSM_MEDIA_ALIGN(stride * 4 / 3, alignment);
+		break;
+	case MSM_VIDC_FMT_P010:
+		alignment = 256;
+		stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return stride;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_y_stride_pix(unsigned int colorformat,
+					      unsigned int width)
+{
+	unsigned int alignment, stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12C:
+	case MSM_VIDC_FMT_P010:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		alignment = 192;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	default:
+		break;
+	}
+
+invalid_input:
+	return stride;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_uv_stride_bytes(unsigned int colorformat,
+						 unsigned int width)
+{
+	unsigned int alignment, stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV12C:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		alignment = 256;
+		stride = MSM_MEDIA_ALIGN(width, 192);
+		stride = MSM_MEDIA_ALIGN(stride * 4 / 3, alignment);
+		break;
+	case MSM_VIDC_FMT_P010:
+		alignment = 256;
+		stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return stride;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_uv_stride_pix(unsigned int colorformat,
+					       unsigned int width)
+{
+	unsigned int alignment, stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV12C:
+	case MSM_VIDC_FMT_P010:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		alignment = 192;
+		stride = MSM_MEDIA_ALIGN(width, alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return stride;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @height
+ * Progressive: height
+ * Interlaced: (height+1)>>1
+ */
+static inline unsigned int video_y_scanlines(unsigned int colorformat,
+					     unsigned int height)
+{
+	unsigned int alignment, sclines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12C:
+	case MSM_VIDC_FMT_P010:
+		alignment = 32;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		alignment = 16;
+		break;
+	default:
+		return 0;
+	}
+	sclines = MSM_MEDIA_ALIGN(height, alignment);
+invalid_input:
+	return sclines;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @height
+ * Progressive: height
+ * Interlaced: (height+1)>>1
+ */
+static inline unsigned int video_uv_scanlines(unsigned int colorformat,
+					      unsigned int height)
+{
+	unsigned int alignment, sclines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_TP10C:
+	case MSM_VIDC_FMT_P010:
+		alignment = 16;
+		break;
+	case MSM_VIDC_FMT_NV12C:
+		alignment = 32;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, alignment);
+
+invalid_input:
+	return sclines;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_y_meta_stride(unsigned int colorformat,
+					       unsigned int width)
+{
+	int y_tile_width = 0, y_meta_stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12C:
+		y_tile_width = 32;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		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;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @height
+ * Progressive: height
+ * Interlaced: (height+1)>>1
+ */
+static inline unsigned int video_y_meta_scanlines(unsigned int colorformat,
+						  unsigned int height)
+{
+	int y_tile_height = 0, y_meta_scanlines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12C:
+		y_tile_height = 8;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		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;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @width
+ * Progressive: width
+ * Interlaced: width
+ */
+static inline unsigned int video_uv_meta_stride(unsigned int colorformat,
+						unsigned int width)
+{
+	int uv_tile_width = 0, uv_meta_stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12C:
+		uv_tile_width = 16;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		uv_tile_width = 24;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	uv_meta_stride = MSM_MEDIA_ROUNDUP((width + 1) >> 1, uv_tile_width);
+	uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64);
+
+invalid_input:
+	return uv_meta_stride;
+}
+
+/*
+ * Function arguments:
+ * @v4l2_fmt
+ * @height
+ * Progressive: height
+ * Interlaced: (height+1)>>1
+ */
+static inline unsigned int video_uv_meta_scanlines(unsigned int colorformat,
+						   unsigned int height)
+{
+	int uv_tile_height = 0, uv_meta_scanlines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12C:
+		uv_tile_height = 8;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		uv_tile_height = 4;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	uv_meta_scanlines = MSM_MEDIA_ROUNDUP((height + 1) >> 1, uv_tile_height);
+	uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16);
+
+invalid_input:
+	return uv_meta_scanlines;
+}
+
+static inline unsigned int video_rgb_stride_bytes(unsigned int colorformat,
+						  unsigned int width)
+{
+	unsigned int alignment = 0, stride = 0, bpp = 4;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_RGBA8888C:
+	case MSM_VIDC_FMT_RGBA8888:
+		alignment = 256;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	stride = MSM_MEDIA_ALIGN(width * bpp, alignment);
+
+invalid_input:
+	return stride;
+}
+
+static inline unsigned int video_rgb_stride_pix(unsigned int colorformat,
+						unsigned int width)
+{
+	unsigned int bpp = 4;
+
+	return video_rgb_stride_bytes(colorformat, width) / bpp;
+}
+
+static inline unsigned int video_rgb_scanlines(unsigned int colorformat,
+					       unsigned int height)
+{
+	unsigned int alignment = 0, scanlines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_RGBA8888C:
+		alignment = 16;
+		break;
+	case MSM_VIDC_FMT_RGBA8888:
+		alignment = 32;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	scanlines = MSM_MEDIA_ALIGN(height, alignment);
+
+invalid_input:
+	return scanlines;
+}
+
+static inline unsigned int video_rgb_meta_stride(unsigned int colorformat,
+						 unsigned int width)
+{
+	int rgb_tile_width = 0, rgb_meta_stride = 0;
+
+	if (!width)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_RGBA8888C:
+	case MSM_VIDC_FMT_RGBA8888:
+		rgb_tile_width = 16;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, rgb_tile_width);
+	rgb_meta_stride = MSM_MEDIA_ALIGN(rgb_meta_stride, 64);
+
+invalid_input:
+	return rgb_meta_stride;
+}
+
+static inline unsigned int video_rgb_meta_scanlines(unsigned int colorformat,
+						    unsigned int height)
+{
+	int rgb_tile_height = 0, rgb_meta_scanlines = 0;
+
+	if (!height)
+		goto invalid_input;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_RGBA8888C:
+	case MSM_VIDC_FMT_RGBA8888:
+		rgb_tile_height = 4;
+		break;
+	default:
+		goto invalid_input;
+	}
+
+	rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, rgb_tile_height);
+	rgb_meta_scanlines = MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16);
+
+invalid_input:
+	return rgb_meta_scanlines;
+}
+
+static inline unsigned int video_buffer_size(unsigned int colorformat, unsigned int pix_width,
+					     unsigned int pix_height, unsigned int interlace)
+{
+	unsigned int 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;
+	unsigned int rgb_stride = 0, rgb_scanlines = 0;
+	unsigned int rgb_plane = 0, rgb_ubwc_plane = 0, rgb_meta_plane = 0;
+	unsigned int rgb_meta_stride = 0, rgb_meta_scanlines = 0;
+
+	if (!pix_width || !pix_height)
+		goto invalid_input;
+
+	y_stride = video_y_stride_bytes(colorformat, pix_width);
+	uv_stride = video_uv_stride_bytes(colorformat, pix_width);
+	y_sclines = video_y_scanlines(colorformat, pix_height);
+	uv_sclines = video_uv_scanlines(colorformat, pix_height);
+	rgb_stride = video_rgb_stride_bytes(colorformat, pix_width);
+	rgb_scanlines = video_rgb_scanlines(colorformat, pix_height);
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV21:
+	case MSM_VIDC_FMT_NV12:
+	case MSM_VIDC_FMT_P010:
+		y_plane = y_stride * y_sclines;
+		uv_plane = uv_stride * uv_sclines;
+		size = y_plane + uv_plane;
+		break;
+	case MSM_VIDC_FMT_NV12C:
+		y_meta_stride = video_y_meta_stride(colorformat, pix_width);
+		uv_meta_stride = video_uv_meta_stride(colorformat, pix_width);
+		if (!interlace && colorformat == MSM_VIDC_FMT_NV12C) {
+			y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
+			uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
+			y_meta_scanlines =
+				video_y_meta_scanlines(colorformat, pix_height);
+			y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scanlines, 4096);
+			uv_meta_scanlines =
+				video_uv_meta_scanlines(colorformat, pix_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);
+		} else {
+			if (pix_width <= INTERLACE_WIDTH_MAX &&
+			    pix_height <= INTERLACE_HEIGHT_MAX &&
+			    (pix_height * pix_width) / 256 <= INTERLACE_MB_PER_FRAME_MAX) {
+				y_sclines =
+					video_y_scanlines(colorformat, (pix_height + 1) >> 1);
+				y_ubwc_plane =
+					MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
+				uv_sclines =
+					video_uv_scanlines(colorformat, (pix_height + 1) >> 1);
+				uv_ubwc_plane =
+					MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
+				y_meta_scanlines =
+				video_y_meta_scanlines(colorformat, (pix_height + 1) >> 1);
+				y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scanlines,
+							       4096);
+				uv_meta_scanlines =
+				video_uv_meta_scanlines(colorformat, (pix_height + 1) >> 1);
+				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) * 2;
+			} else {
+				y_sclines = video_y_scanlines(colorformat, pix_height);
+				y_ubwc_plane =
+					MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
+				uv_sclines = video_uv_scanlines(colorformat, pix_height);
+				uv_ubwc_plane =
+					MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
+				y_meta_scanlines =
+					video_y_meta_scanlines(colorformat, pix_height);
+				y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scanlines,
+							       4096);
+				uv_meta_scanlines =
+					video_uv_meta_scanlines(colorformat, pix_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);
+			}
+		}
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		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 = video_y_meta_stride(colorformat, pix_width);
+		y_meta_scanlines = video_y_meta_scanlines(colorformat, pix_height);
+		y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scanlines, 4096);
+		uv_meta_stride = video_uv_meta_stride(colorformat, pix_width);
+		uv_meta_scanlines = video_uv_meta_scanlines(colorformat, pix_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;
+		break;
+	case MSM_VIDC_FMT_RGBA8888C:
+		rgb_ubwc_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096);
+		rgb_meta_stride = video_rgb_meta_stride(colorformat, pix_width);
+		rgb_meta_scanlines = video_rgb_meta_scanlines(colorformat, pix_height);
+		rgb_meta_plane = MSM_MEDIA_ALIGN(rgb_meta_stride * rgb_meta_scanlines, 4096);
+		size = rgb_ubwc_plane + rgb_meta_plane;
+		break;
+	case MSM_VIDC_FMT_RGBA8888:
+		rgb_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096);
+		size = rgb_plane;
+		break;
+	default:
+		break;
+	}
+
+invalid_input:
+	size = MSM_MEDIA_ALIGN(size, 4096);
+	return size;
+}
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 17/33] iris: vidc: define various structures and enum
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (15 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 16/33] iris: add helpers for media format Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI) Vikash Garodia
                   ` (18 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

Define various structures and enums used by driver like
core capability, instance capability, color space info,
buffer types etc.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../qcom/iris/vidc/inc/msm_vidc_internal.h         | 787 +++++++++++++++++++++
 1 file changed, 787 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
new file mode 100644
index 0000000..4d54834
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
@@ -0,0 +1,787 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/bits.h>
+#include <linux/spinlock.h>
+#include <linux/sync_file.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+struct msm_vidc_core;
+struct msm_vidc_inst;
+
+static const char video_banner[] = "Video-Banner: (" __stringify(VIDEO_COMPILE_BY) "@"
+	__stringify(VIDEO_COMPILE_HOST) ") (" __stringify(VIDEO_COMPILE_TIME) ")";
+
+#define MAX_NAME_LENGTH   128
+#define VENUS_VERSION_LENGTH 128
+#define MAX_MATRIX_COEFFS 9
+#define MAX_BIAS_COEFFS   3
+#define MAX_LIMIT_COEFFS  6
+#define MAX_DEBUGFS_NAME  50
+#define DEFAULT_HEIGHT    240
+#define DEFAULT_WIDTH     320
+#define DEFAULT_FPS       30
+#define MAXIMUM_VP9_FPS   60
+#define RT_DEC_DOWN_PRORITY_OFFSET 1
+#define MAX_SUPPORTED_INSTANCES  16
+#define DEFAULT_BSE_VPP_DELAY    2
+#define MAX_CAP_PARENTS          20
+#define MAX_CAP_CHILDREN         20
+#define DEFAULT_MAX_HOST_BUF_COUNT  64
+#define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256
+#define BIT_DEPTH_8 (8 << 16 | 8)
+#define BIT_DEPTH_10 (10 << 16 | 10)
+#define CODED_FRAMES_PROGRESSIVE 0x0
+#define CODED_FRAMES_INTERLACE 0x1
+#define MAX_VP9D_INST_COUNT     6
+/* TODO: move below macros to waipio.c */
+#define MAX_ENH_LAYER_HB        3
+#define MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW         5
+#define MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW     3
+#define MAX_AVC_ENH_LAYER_SLIDING_WINDOW      3
+#define MAX_AVC_ENH_LAYER_HYBRID_HP           5
+#define INVALID_DEFAULT_MARK_OR_USE_LTR      -1
+#define MAX_SLICES_PER_FRAME                 10
+#define MAX_SLICES_FRAME_RATE                60
+#define MAX_MB_SLICE_WIDTH                 4096
+#define MAX_MB_SLICE_HEIGHT                2160
+#define MAX_BYTES_SLICE_WIDTH              1920
+#define MAX_BYTES_SLICE_HEIGHT             1088
+#define MIN_HEVC_SLICE_WIDTH                384
+#define MIN_AVC_SLICE_WIDTH                 192
+#define MIN_SLICE_HEIGHT                    128
+#define MAX_BITRATE_BOOST                    25
+#define MAX_SUPPORTED_MIN_QUALITY            70
+#define MIN_CHROMA_QP_OFFSET                -12
+#define MAX_CHROMA_QP_OFFSET                  0
+#define MIN_QP_10BIT                        -11
+#define MIN_QP_8BIT                           1
+#define INVALID_FD                           -1
+#define MAX_ENCODING_REFERNCE_FRAMES          7
+#define MAX_LTR_FRAME_COUNT_5                 5
+#define MAX_LTR_FRAME_COUNT_2                 2
+#define MAX_ENC_RING_BUF_COUNT                5 /* to be tuned */
+#define MAX_TRANSCODING_STATS_FRAME_RATE     60
+#define MAX_TRANSCODING_STATS_WIDTH        4096
+#define MAX_TRANSCODING_STATS_HEIGHT       2304
+
+#define DCVS_WINDOW 16
+#define ENC_FPS_WINDOW 3
+#define DEC_FPS_WINDOW 10
+#define INPUT_TIMER_LIST_SIZE 30
+
+#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+#define OUTPUT_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+
+#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 * 4)
+
+#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))
+
+#ifdef V4L2_CTRL_CLASS_CODEC
+#define IS_PRIV_CTRL(idx) ( \
+	(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_CODEC) && \
+	V4L2_CTRL_DRIVER_PRIV(idx))
+#else
+#define IS_PRIV_CTRL(idx) ( \
+	(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \
+	V4L2_CTRL_DRIVER_PRIV(idx))
+#endif
+
+#define BUFFER_ALIGNMENT_SIZE(x) x
+#define NUM_MBS_360P (((480 + 15) >> 4) * ((360 + 15) >> 4))
+#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4))
+#define NUM_MBS_4k (((4096 + 15) >> 4) * ((2304 + 15) >> 4))
+#define MB_SIZE_IN_PIXEL (16 * 16)
+
+#define DB_H264_DISABLE_SLICE_BOUNDARY \
+		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+
+#define DB_HEVC_DISABLE_SLICE_BOUNDARY \
+		V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+
+/*
+ * Convert Q16 number into Integer and Fractional part up to 2 places.
+ * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
+ * Integer part =  105752 / 65536 = 1;
+ * Reminder = 105752 * 0xFFFF = 40216; Last 16 bits.
+ * Fractional part = 40216 * 100 / 65536 = 61;
+ * Now convert to FP(1, 61, 100).
+ */
+#define Q16_INT(q) ((q) >> 16)
+#define Q16_FRAC(q) ((((q) & 0xFFFF) * 100) >> 16)
+
+/* define timeout values */
+#define HW_RESPONSE_TIMEOUT_VALUE     (1000)
+#define SW_PC_DELAY_VALUE             (HW_RESPONSE_TIMEOUT_VALUE + 500)
+#define FW_UNLOAD_DELAY_VALUE         (SW_PC_DELAY_VALUE + 1500)
+
+#define MAX_DPB_COUNT 32
+ /*
+  * max dpb count in firmware = 16
+  * each dpb: 4 words - <base_address, addr_offset, data_offset>
+  * dpb list array size = 16 * 4
+  * dpb payload size = 16 * 4 * 4
+  */
+#define MAX_DPB_LIST_ARRAY_SIZE (16 * 4)
+#define MAX_DPB_LIST_PAYLOAD_SIZE (16 * 4 * 4)
+
+enum msm_vidc_domain_type {
+	MSM_VIDC_ENCODER           = BIT(0),
+	MSM_VIDC_DECODER           = BIT(1),
+};
+
+enum msm_vidc_codec_type {
+	MSM_VIDC_H264              = BIT(0),
+	MSM_VIDC_HEVC              = BIT(1),
+	MSM_VIDC_VP9               = BIT(2),
+};
+
+enum msm_vidc_colorformat_type {
+	MSM_VIDC_FMT_NONE          = 0,
+	MSM_VIDC_FMT_NV12C         = BIT(0),
+	MSM_VIDC_FMT_NV12          = BIT(1),
+	MSM_VIDC_FMT_NV21          = BIT(2),
+	MSM_VIDC_FMT_TP10C         = BIT(3),
+	MSM_VIDC_FMT_P010          = BIT(4),
+	MSM_VIDC_FMT_RGBA8888C     = BIT(5),
+	MSM_VIDC_FMT_RGBA8888      = BIT(6),
+};
+
+enum msm_vidc_buffer_type {
+	MSM_VIDC_BUF_NONE,
+	MSM_VIDC_BUF_INPUT,
+	MSM_VIDC_BUF_OUTPUT,
+	MSM_VIDC_BUF_READ_ONLY,
+	MSM_VIDC_BUF_INTERFACE_QUEUE,
+	MSM_VIDC_BUF_BIN,
+	MSM_VIDC_BUF_ARP,
+	MSM_VIDC_BUF_COMV,
+	MSM_VIDC_BUF_NON_COMV,
+	MSM_VIDC_BUF_LINE,
+	MSM_VIDC_BUF_DPB,
+	MSM_VIDC_BUF_PERSIST,
+	MSM_VIDC_BUF_VPSS,
+};
+
+/* always match with v4l2 flags V4L2_BUF_FLAG_* */
+enum msm_vidc_buffer_flags {
+	MSM_VIDC_BUF_FLAG_KEYFRAME         = 0x00000008,
+	MSM_VIDC_BUF_FLAG_PFRAME           = 0x00000010,
+	MSM_VIDC_BUF_FLAG_BFRAME           = 0x00000020,
+	MSM_VIDC_BUF_FLAG_ERROR            = 0x00000040,
+	MSM_VIDC_BUF_FLAG_LAST             = 0x00100000,
+};
+
+enum msm_vidc_buffer_attributes {
+	MSM_VIDC_ATTR_DEFERRED                  = BIT(0),
+	MSM_VIDC_ATTR_READ_ONLY                 = BIT(1),
+	MSM_VIDC_ATTR_PENDING_RELEASE           = BIT(2),
+	MSM_VIDC_ATTR_QUEUED                    = BIT(3),
+	MSM_VIDC_ATTR_DEQUEUED                  = BIT(4),
+	MSM_VIDC_ATTR_BUFFER_DONE               = BIT(5),
+	MSM_VIDC_ATTR_RELEASE_ELIGIBLE          = BIT(6),
+};
+
+enum msm_vidc_buffer_region {
+	MSM_VIDC_REGION_NONE = 0,
+	MSM_VIDC_NON_SECURE,
+	MSM_VIDC_NON_SECURE_PIXEL,
+	MSM_VIDC_SECURE_PIXEL,
+	MSM_VIDC_SECURE_NONPIXEL,
+	MSM_VIDC_SECURE_BITSTREAM,
+	MSM_VIDC_REGION_MAX,
+};
+
+enum msm_vidc_port_type {
+	INPUT_PORT = 0,
+	OUTPUT_PORT,
+	PORT_NONE,
+	MAX_PORT,
+};
+
+enum msm_vidc_stage_type {
+	MSM_VIDC_STAGE_NONE = 0,
+	MSM_VIDC_STAGE_1 = 1,
+	MSM_VIDC_STAGE_2 = 2,
+};
+
+enum msm_vidc_pipe_type {
+	MSM_VIDC_PIPE_NONE = 0,
+	MSM_VIDC_PIPE_1 = 1,
+	MSM_VIDC_PIPE_2 = 2,
+	MSM_VIDC_PIPE_4 = 4,
+};
+
+enum msm_vidc_quality_mode {
+	MSM_VIDC_MAX_QUALITY_MODE = 0x1,
+	MSM_VIDC_POWER_SAVE_MODE = 0x2,
+};
+
+enum msm_vidc_color_primaries {
+	MSM_VIDC_PRIMARIES_RESERVED                         = 0,
+	MSM_VIDC_PRIMARIES_BT709                            = 1,
+	MSM_VIDC_PRIMARIES_UNSPECIFIED                      = 2,
+	MSM_VIDC_PRIMARIES_BT470_SYSTEM_M                   = 4,
+	MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG                  = 5,
+	MSM_VIDC_PRIMARIES_BT601_525                        = 6,
+	MSM_VIDC_PRIMARIES_SMPTE_ST240M                     = 7,
+	MSM_VIDC_PRIMARIES_GENERIC_FILM                     = 8,
+	MSM_VIDC_PRIMARIES_BT2020                           = 9,
+	MSM_VIDC_PRIMARIES_SMPTE_ST428_1                    = 10,
+	MSM_VIDC_PRIMARIES_SMPTE_RP431_2                    = 11,
+	MSM_VIDC_PRIMARIES_SMPTE_EG431_1                    = 12,
+	MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH                   = 22,
+};
+
+enum msm_vidc_transfer_characteristics {
+	MSM_VIDC_TRANSFER_RESERVED                          = 0,
+	MSM_VIDC_TRANSFER_BT709                             = 1,
+	MSM_VIDC_TRANSFER_UNSPECIFIED                       = 2,
+	MSM_VIDC_TRANSFER_BT470_SYSTEM_M                    = 4,
+	MSM_VIDC_TRANSFER_BT470_SYSTEM_BG                   = 5,
+	MSM_VIDC_TRANSFER_BT601_525_OR_625                  = 6,
+	MSM_VIDC_TRANSFER_SMPTE_ST240M                      = 7,
+	MSM_VIDC_TRANSFER_LINEAR                            = 8,
+	MSM_VIDC_TRANSFER_LOG_100_1                         = 9,
+	MSM_VIDC_TRANSFER_LOG_SQRT                          = 10,
+	MSM_VIDC_TRANSFER_XVYCC                             = 11,
+	MSM_VIDC_TRANSFER_BT1361_0                          = 12,
+	MSM_VIDC_TRANSFER_SRGB_SYCC                         = 13,
+	MSM_VIDC_TRANSFER_BT2020_14                         = 14,
+	MSM_VIDC_TRANSFER_BT2020_15                         = 15,
+	MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ                   = 16,
+	MSM_VIDC_TRANSFER_SMPTE_ST428_1                     = 17,
+	MSM_VIDC_TRANSFER_BT2100_2_HLG                      = 18,
+};
+
+enum msm_vidc_matrix_coefficients {
+	MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1             = 0,
+	MSM_VIDC_MATRIX_COEFF_BT709                          = 1,
+	MSM_VIDC_MATRIX_COEFF_UNSPECIFIED                    = 2,
+	MSM_VIDC_MATRIX_COEFF_RESERVED                       = 3,
+	MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47                   = 4,
+	MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625      = 5,
+	MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625    = 6,
+	MSM_VIDC_MATRIX_COEFF_SMPTE_ST240                    = 7,
+	MSM_VIDC_MATRIX_COEFF_YCGCO                          = 8,
+	MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT            = 9,
+	MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT                = 10,
+	MSM_VIDC_MATRIX_COEFF_SMPTE_ST2085                   = 11,
+	MSM_VIDC_MATRIX_COEFF_SMPTE_CHROM_DERV_NON_CONSTANT  = 12,
+	MSM_VIDC_MATRIX_COEFF_SMPTE_CHROM_DERV_CONSTANT      = 13,
+	MSM_VIDC_MATRIX_COEFF_BT2100                         = 14,
+};
+
+enum msm_vidc_preprocess_type {
+	MSM_VIDC_PREPROCESS_NONE = BIT(0),
+	MSM_VIDC_PREPROCESS_TYPE0 = BIT(1),
+};
+
+enum msm_vidc_core_capability_type {
+	CORE_CAP_NONE = 0,
+	ENC_CODECS,
+	DEC_CODECS,
+	MAX_SESSION_COUNT,
+	MAX_NUM_720P_SESSIONS,
+	MAX_NUM_1080P_SESSIONS,
+	MAX_NUM_4K_SESSIONS,
+	MAX_NUM_8K_SESSIONS,
+	MAX_LOAD,
+	MAX_RT_MBPF,
+	MAX_MBPF,
+	MAX_MBPS,
+	MAX_MBPF_HQ,
+	MAX_MBPS_HQ,
+	MAX_MBPF_B_FRAME,
+	MAX_MBPS_B_FRAME,
+	MAX_MBPS_ALL_INTRA,
+	MAX_ENH_LAYER_COUNT,
+	NUM_VPP_PIPE,
+	SW_PC,
+	SW_PC_DELAY,
+	FW_UNLOAD,
+	FW_UNLOAD_DELAY,
+	HW_RESPONSE_TIMEOUT,
+	PREFIX_BUF_COUNT_PIX,
+	PREFIX_BUF_SIZE_PIX,
+	PREFIX_BUF_COUNT_NON_PIX,
+	PREFIX_BUF_SIZE_NON_PIX,
+	PAGEFAULT_NON_FATAL,
+	PAGETABLE_CACHING,
+	DCVS,
+	DECODE_BATCH,
+	DECODE_BATCH_TIMEOUT,
+	STATS_TIMEOUT_MS,
+	AV_SYNC_WINDOW_SIZE,
+	CLK_FREQ_THRESHOLD,
+	NON_FATAL_FAULTS,
+	DEVICE_CAPS,
+	CORE_CAP_MAX,
+};
+
+/**
+ * msm_vidc_prepare_dependency_list() api will prepare caps_list by looping over
+ * enums(msm_vidc_inst_capability_type) from 0 to INST_CAP_MAX and arranges the
+ * node in such a way that parents willbe at the front and dependent children
+ * in the back.
+ *
+ * caps_list preparation may become CPU intensive task, so to save CPU cycles,
+ * organize enum in proper order(leaf caps at the beginning and dependent parent caps
+ * at back), so that during caps_list preparation num CPU cycles spent will reduce.
+ *
+ * Note: It will work, if enum kept at different places, but not efficient.
+ *
+ * - place all leaf(no child) enums before PROFILE cap.
+ * - place all intermittent(having both parent and child) enums before FRAME_WIDTH cap.
+ * - place all root(no parent) enums before INST_CAP_MAX cap.
+ */
+
+enum msm_vidc_inst_capability_type {
+	INST_CAP_NONE = 0,
+	MIN_FRAME_QP,
+	MAX_FRAME_QP,
+	I_FRAME_QP,
+	P_FRAME_QP,
+	B_FRAME_QP,
+	TIME_DELTA_BASED_RC,
+	CONSTANT_QUALITY,
+	VBV_DELAY,
+	PEAK_BITRATE,
+	ENTROPY_MODE,
+	TRANSFORM_8X8,
+	STAGE,
+	LTR_COUNT,
+	IR_PERIOD,
+	BITRATE_BOOST,
+	OUTPUT_ORDER,
+	INPUT_BUF_HOST_MAX_COUNT,
+	OUTPUT_BUF_HOST_MAX_COUNT,
+	VUI_TIMING_INFO,
+	SLICE_DECODE,
+	PROFILE,
+	ENH_LAYER_COUNT,
+	BIT_RATE,
+	GOP_SIZE,
+	B_FRAME,
+	ALL_INTRA,
+	MIN_QUALITY,
+	SLICE_MODE,
+	FRAME_WIDTH,
+	LOSSLESS_FRAME_WIDTH,
+	FRAME_HEIGHT,
+	LOSSLESS_FRAME_HEIGHT,
+	PIX_FMTS,
+	MIN_BUFFERS_INPUT,
+	MIN_BUFFERS_OUTPUT,
+	MBPF,
+	BATCH_MBPF,
+	BATCH_FPS,
+	LOSSLESS_MBPF,
+	FRAME_RATE,
+	OPERATING_RATE,
+	INPUT_RATE,
+	TIMESTAMP_RATE,
+	SCALE_FACTOR,
+	MB_CYCLES_VSP,
+	MB_CYCLES_VPP,
+	MB_CYCLES_LP,
+	MB_CYCLES_FW,
+	MB_CYCLES_FW_VPP,
+	ENC_RING_BUFFER_COUNT,
+	HFLIP,
+	VFLIP,
+	ROTATION,
+	HEADER_MODE,
+	PREPEND_SPSPPS_TO_IDR,
+	WITHOUT_STARTCODE,
+	NAL_LENGTH_FIELD,
+	REQUEST_I_FRAME,
+	BITRATE_MODE,
+	LOSSLESS,
+	FRAME_SKIP_MODE,
+	FRAME_RC_ENABLE,
+	GOP_CLOSURE,
+	USE_LTR,
+	MARK_LTR,
+	BASELAYER_PRIORITY,
+	IR_TYPE,
+	AU_DELIMITER,
+	GRID_ENABLE,
+	GRID_SIZE,
+	I_FRAME_MIN_QP,
+	P_FRAME_MIN_QP,
+	B_FRAME_MIN_QP,
+	I_FRAME_MAX_QP,
+	P_FRAME_MAX_QP,
+	B_FRAME_MAX_QP,
+	LAYER_TYPE,
+	LAYER_ENABLE,
+	L0_BR,
+	L1_BR,
+	L2_BR,
+	L3_BR,
+	L4_BR,
+	L5_BR,
+	LEVEL,
+	HEVC_TIER,
+	DISPLAY_DELAY_ENABLE,
+	DISPLAY_DELAY,
+	CONCEAL_COLOR_8BIT,
+	CONCEAL_COLOR_10BIT,
+	LF_MODE,
+	LF_ALPHA,
+	LF_BETA,
+	SLICE_MAX_BYTES,
+	SLICE_MAX_MB,
+	MB_RC,
+	CHROMA_QP_INDEX_OFFSET,
+	PIPE,
+	POC,
+	CODED_FRAMES,
+	BIT_DEPTH,
+	BITSTREAM_SIZE_OVERWRITE,
+	DEFAULT_HEADER,
+	RAP_FRAME,
+	SEQ_CHANGE_AT_SYNC_FRAME,
+	QUALITY_MODE,
+	CABAC_MAX_BITRATE,
+	CAVLC_MAX_BITRATE,
+	ALLINTRA_MAX_BITRATE,
+	NUM_COMV,
+	SIGNAL_COLOR_INFO,
+	INST_CAP_MAX,
+};
+
+enum msm_vidc_inst_capability_flags {
+	CAP_FLAG_NONE                    = 0,
+	CAP_FLAG_DYNAMIC_ALLOWED         = BIT(0),
+	CAP_FLAG_MENU                    = BIT(1),
+	CAP_FLAG_INPUT_PORT              = BIT(2),
+	CAP_FLAG_OUTPUT_PORT             = BIT(3),
+	CAP_FLAG_CLIENT_SET              = BIT(4),
+	CAP_FLAG_BITMASK                 = BIT(5),
+	CAP_FLAG_VOLATILE                = BIT(6),
+};
+
+struct msm_vidc_inst_cap {
+	enum msm_vidc_inst_capability_type cap_id;
+	s32 min;
+	s32 max;
+	u32 step_or_mask;
+	s32 value;
+	u32 v4l2_id;
+	u32 hfi_id;
+	enum msm_vidc_inst_capability_flags flags;
+	enum msm_vidc_inst_capability_type children[MAX_CAP_CHILDREN];
+	int (*adjust)(void *inst,
+		      struct v4l2_ctrl *ctrl);
+	int (*set)(void *inst,
+		   enum msm_vidc_inst_capability_type cap_id);
+};
+
+struct msm_vidc_inst_capability {
+	enum msm_vidc_domain_type domain;
+	enum msm_vidc_codec_type codec;
+	struct msm_vidc_inst_cap cap[INST_CAP_MAX + 1];
+};
+
+struct msm_vidc_core_capability {
+	enum msm_vidc_core_capability_type type;
+	u32 value;
+};
+
+struct msm_vidc_inst_cap_entry {
+	/* list of struct msm_vidc_inst_cap_entry */
+	struct list_head list;
+	enum msm_vidc_inst_capability_type cap_id;
+};
+
+struct msm_vidc_event_data {
+	union {
+		bool                         bval;
+		u32                          uval;
+		u64                          uval64;
+		s32                          val;
+		s64                          val64;
+		void                        *ptr;
+	} edata;
+};
+
+struct debug_buf_count {
+	u64 etb;
+	u64 ftb;
+	u64 fbd;
+	u64 ebd;
+};
+
+struct msm_vidc_statistics {
+	struct debug_buf_count             count;
+	u64                                data_size;
+	u64                                time_ms;
+	u32                                avg_bw_llcc;
+	u32                                avg_bw_ddr;
+};
+
+enum msm_vidc_cache_op {
+	MSM_VIDC_CACHE_CLEAN,
+	MSM_VIDC_CACHE_INVALIDATE,
+	MSM_VIDC_CACHE_CLEAN_INVALIDATE,
+};
+
+enum msm_vidc_dcvs_flags {
+	MSM_VIDC_DCVS_INCR               = BIT(0),
+	MSM_VIDC_DCVS_DECR               = BIT(1),
+};
+
+enum msm_vidc_clock_properties {
+	CLOCK_PROP_HAS_SCALING           = BIT(0),
+	CLOCK_PROP_HAS_MEM_RETENTION     = BIT(1),
+};
+
+enum signal_session_response {
+	SIGNAL_CMD_STOP_INPUT = 0,
+	SIGNAL_CMD_STOP_OUTPUT,
+	SIGNAL_CMD_CLOSE,
+	MAX_SIGNAL,
+};
+
+struct msm_vidc_input_cr_data {
+	struct list_head       list;
+	u32                    index;
+	u32                    input_cr;
+};
+
+struct msm_vidc_session_idle {
+	bool                   idle;
+	u64                    last_activity_time_ns;
+};
+
+struct msm_vidc_color_info {
+	u32 colorspace;
+	u32 ycbcr_enc;
+	u32 xfer_func;
+	u32 quantization;
+};
+
+struct msm_vidc_rectangle {
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
+struct msm_vidc_subscription_params {
+	u32                    bitstream_resolution;
+	u32                    crop_offsets[2];
+	u32                    bit_depth;
+	u32                    coded_frames;
+	u32                    fw_min_count;
+	u32                    pic_order_cnt;
+	u32                    color_info;
+	u32                    profile;
+	u32                    level;
+	u32                    tier;
+};
+
+struct msm_vidc_hfi_frame_info {
+	u32                    picture_type;
+	u32                    no_output;
+	u32                    subframe_input;
+	u32                    cr;
+	u32                    cf;
+	u32                    data_corrupt;
+	u32                    overflow;
+};
+
+struct msm_vidc_decode_vpp_delay {
+	bool                   enable;
+	u32                    size;
+};
+
+struct msm_vidc_decode_batch {
+	bool                   enable;
+	u32                    size;
+	struct delayed_work    work;
+};
+
+enum msm_vidc_power_mode {
+	VIDC_POWER_NORMAL = 0,
+	VIDC_POWER_LOW,
+	VIDC_POWER_TURBO,
+};
+
+struct vidc_bus_vote_data {
+	enum msm_vidc_domain_type domain;
+	enum msm_vidc_codec_type codec;
+	enum msm_vidc_power_mode power_mode;
+	u32 color_formats[2];
+	int num_formats; /* 1 = DPB-OPB unified; 2 = split */
+	int input_height, input_width, bitrate;
+	int output_height, output_width;
+	int rotation;
+	int compression_ratio;
+	int complexity_factor;
+	int input_cr;
+	u32 lcu_size;
+	u32 fps;
+	u32 work_mode;
+	bool use_sys_cache;
+	bool b_frames_enabled;
+	u64 calc_bw_ddr;
+	u64 calc_bw_llcc;
+	u32 num_vpp_pipes;
+};
+
+struct msm_vidc_power {
+	enum msm_vidc_power_mode power_mode;
+	u32                    buffer_counter;
+	u32                    min_threshold;
+	u32                    nom_threshold;
+	u32                    max_threshold;
+	bool                   dcvs_mode;
+	u32                    dcvs_window;
+	u64                    min_freq;
+	u64                    curr_freq;
+	u32                    ddr_bw;
+	u32                    sys_cache_bw;
+	u32                    dcvs_flags;
+	u32                    fw_cr;
+	u32                    fw_cf;
+};
+
+struct msm_vidc_mem {
+	struct list_head            list;
+	enum msm_vidc_buffer_type   type;
+	enum msm_vidc_buffer_region region;
+	u32                         size;
+	u8                          secure:1;
+	u8                          map_kernel:1;
+	struct dma_buf             *dmabuf;
+	struct iosys_map            dmabuf_map;
+	void                       *kvaddr;
+	dma_addr_t                  device_addr;
+	unsigned long               attrs;
+	u32                         refcount;
+	struct sg_table            *table;
+	struct dma_buf_attachment  *attach;
+	enum dma_data_direction     direction;
+};
+
+struct msm_vidc_mem_list {
+	struct list_head            list; // list of "struct msm_vidc_mem"
+};
+
+struct msm_vidc_buffer {
+	struct list_head                   list;
+	struct msm_vidc_inst              *inst;
+	enum msm_vidc_buffer_type          type;
+	enum msm_vidc_buffer_region        region;
+	u32                                index;
+	int                                fd;
+	u32                                buffer_size;
+	u32                                data_offset;
+	u32                                data_size;
+	u64                                device_addr;
+	u32                                flags;
+	u64                                timestamp;
+	enum msm_vidc_buffer_attributes    attr;
+	void                              *dmabuf;
+	struct sg_table                   *sg_table;
+	struct dma_buf_attachment         *attach;
+	u32                                dbuf_get:1;
+	u32                                start_time_ms;
+	u32                                end_time_ms;
+};
+
+struct msm_vidc_buffers {
+	struct list_head       list; // list of "struct msm_vidc_buffer"
+	u32                    min_count;
+	u32                    extra_count;
+	u32                    actual_count;
+	u32                    size;
+	bool                   reuse;
+};
+
+struct msm_vidc_buffer_stats {
+	struct list_head                   list;
+	u32                                frame_num;
+	u64                                timestamp;
+	u32                                etb_time_ms;
+	u32                                ebd_time_ms;
+	u32                                ftb_time_ms;
+	u32                                fbd_time_ms;
+	u32                                data_size;
+	u32                                flags;
+	u32                                ts_offset;
+};
+
+enum msm_vidc_buffer_stats_flag {
+	MSM_VIDC_STATS_FLAG_CORRUPT        = BIT(0),
+	MSM_VIDC_STATS_FLAG_OVERFLOW       = BIT(1),
+	MSM_VIDC_STATS_FLAG_NO_OUTPUT      = BIT(2),
+	MSM_VIDC_STATS_FLAG_SUBFRAME_INPUT = BIT(3),
+};
+
+struct msm_vidc_sort {
+	struct list_head       list;
+	s64                    val;
+};
+
+struct msm_vidc_timestamp {
+	struct msm_vidc_sort   sort;
+	u64                    rank;
+};
+
+struct msm_vidc_timestamps {
+	struct list_head       list;
+	u32                    count;
+	u64                    rank;
+};
+
+struct msm_vidc_input_timer {
+	struct list_head       list;
+	u64                    time_us;
+};
+
+enum msm_vidc_allow {
+	MSM_VIDC_DISALLOW,
+	MSM_VIDC_ALLOW,
+	MSM_VIDC_DEFER,
+	MSM_VIDC_DISCARD,
+	MSM_VIDC_IGNORE,
+};
+
+struct msm_vidc_sfr {
+	u32 bufsize;
+	u8 rg_data[];
+};
+
+struct msm_vidc_ctrl_data {
+	bool skip_s_ctrl;
+};
+
+#endif // _MSM_VIDC_INTERNAL_H_
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI)
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (16 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 17/33] iris: vidc: define various structures and enum Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 15:58   ` Bryan O'Donoghue
  2023-07-31  9:02   ` Bryan O'Donoghue
  2023-07-28 13:23 ` [PATCH 19/33] iris: vidc: hfi: add Host Firmware Interface (HFI) response handling Vikash Garodia
                   ` (17 subsequent siblings)
  35 siblings, 2 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements the interface for communication between
host driver and firmware through interface commands and messages.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/venus_hfi.h  |   66 +
 .../media/platform/qcom/iris/vidc/src/venus_hfi.c  | 1503 ++++++++++++++++++++
 2 files changed, 1569 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
new file mode 100644
index 0000000..99c504d
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VENUS_HFI_H_
+#define _VENUS_HFI_H_
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/irqreturn.h>
+#include <linux/regulator/consumer.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+#define VIDC_MAX_PC_SKIP_COUNT		10
+
+struct vidc_buffer_addr_info {
+	enum msm_vidc_buffer_type buffer_type;
+	u32 buffer_size;
+	u32 num_buffers;
+	u32 align_device_addr;
+	u32 extradata_addr;
+	u32 extradata_size;
+	u32 response_required;
+};
+
+int __strict_check(struct msm_vidc_core *core,
+		   const char *function);
+int venus_hfi_session_property(struct msm_vidc_inst *inst,
+			       u32 pkt_type, u32 flags, u32 port,
+			       u32 payload_type, void *payload,
+			       u32 payload_size);
+int venus_hfi_session_command(struct msm_vidc_inst *inst,
+			      u32 cmd, enum msm_vidc_port_type port,
+			      u32 payload_type, void *payload, u32 payload_size);
+int venus_hfi_queue_buffer(struct msm_vidc_inst *inst,
+			   struct msm_vidc_buffer *buffer);
+int venus_hfi_release_buffer(struct msm_vidc_inst *inst,
+			     struct msm_vidc_buffer *buffer);
+int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+int venus_hfi_session_close(struct msm_vidc_inst *inst);
+int venus_hfi_session_open(struct msm_vidc_inst *inst);
+int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+int venus_hfi_session_resume(struct msm_vidc_inst *inst,
+			     enum msm_vidc_port_type port, u32 payload);
+int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
+int venus_hfi_session_set_codec(struct msm_vidc_inst *inst);
+int venus_hfi_core_init(struct msm_vidc_core *core);
+int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force);
+int venus_hfi_suspend(struct msm_vidc_core *core);
+int venus_hfi_reserve_hardware(struct msm_vidc_inst *inst, u32 duration);
+int venus_hfi_scale_clocks(struct msm_vidc_inst *inst, u64 freq);
+int venus_hfi_scale_buses(struct msm_vidc_inst *inst, u64 bw_ddr, u64 bw_llcc);
+int venus_hfi_set_ir_period(struct msm_vidc_inst *inst, u32 ir_type,
+			    enum msm_vidc_inst_capability_type cap_id);
+void venus_hfi_pm_work_handler(struct work_struct *work);
+irqreturn_t venus_hfi_isr(int irq, void *data);
+irqreturn_t venus_hfi_isr_handler(int irq, void *data);
+int __prepare_pc(struct msm_vidc_core *core);
+
+#endif // _VENUS_HFI_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
new file mode 100644
index 0000000..87cac76
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
@@ -0,0 +1,1503 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/firmware.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/irqreturn.h>
+#include <linux/of_address.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+#include <linux/soc/qcom/mdt_loader.h>
+#include <linux/soc/qcom/smem.h>
+
+#include "firmware.h"
+#include "hfi_packet.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power.h"
+#include "msm_vidc_state.h"
+#include "venus_hfi.h"
+#include "venus_hfi_queue.h"
+#include "venus_hfi_response.h"
+
+#define update_offset(offset, val)		((offset) += (val))
+#define update_timestamp(ts, val) \
+	do { \
+		do_div((ts), NSEC_PER_USEC); \
+		(ts) += (val); \
+		(ts) *= NSEC_PER_USEC; \
+	} while (0)
+
+static int __resume(struct msm_vidc_core *core);
+static int __suspend(struct msm_vidc_core *core);
+
+static void __fatal_error(bool fatal)
+{
+	WARN_ON(fatal);
+}
+
+int __strict_check(struct msm_vidc_core *core, const char *function)
+{
+	bool fatal = !mutex_is_locked(&core->lock);
+
+	__fatal_error(fatal);
+
+	if (fatal)
+		d_vpr_e("%s: strict check failed\n", function);
+
+	return fatal ? -EINVAL : 0;
+}
+
+static bool __valdiate_session(struct msm_vidc_core *core,
+			       struct msm_vidc_inst *inst, const char *func)
+{
+	bool valid = false;
+	struct msm_vidc_inst *temp;
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return false;
+
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp == inst) {
+			valid = true;
+			break;
+		}
+	}
+	if (!valid)
+		i_vpr_e(inst, "%s: invalid session\n", func);
+
+	return valid;
+}
+
+static void __schedule_power_collapse_work(struct msm_vidc_core *core)
+{
+	if (!core->capabilities[SW_PC].value) {
+		d_vpr_l("software power collapse not enabled\n");
+		return;
+	}
+
+	if (!mod_delayed_work(core->pm_workq, &core->pm_work,
+			      msecs_to_jiffies(core->capabilities[SW_PC_DELAY].value))) {
+		d_vpr_h("power collapse already scheduled\n");
+	} else {
+		d_vpr_l("power collapse scheduled for %d ms\n",
+			core->capabilities[SW_PC_DELAY].value);
+	}
+}
+
+static void __cancel_power_collapse_work(struct msm_vidc_core *core)
+{
+	if (!core->capabilities[SW_PC].value)
+		return;
+
+	cancel_delayed_work(&core->pm_work);
+}
+
+static void __flush_debug_queue(struct msm_vidc_core *core,
+				u8 *packet, u32 packet_size)
+{
+	u8 *log;
+	struct hfi_debug_header *pkt;
+	bool local_packet = false;
+	enum vidc_msg_prio_fw log_level_fw = msm_fw_debug;
+
+	if (!packet || !packet_size) {
+		packet = vzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE);
+		if (!packet) {
+			d_vpr_e("%s: allocation failed\n", __func__);
+			return;
+		}
+		packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
+
+		local_packet = true;
+
+		/*
+		 * Local packet is used when error occurred.
+		 * It is good to print these logs to printk as well.
+		 */
+		log_level_fw |= FW_PRINTK;
+	}
+
+	while (!venus_hfi_queue_dbg_read(core, packet)) {
+		pkt = (struct hfi_debug_header *)packet;
+
+		if (pkt->size < sizeof(struct hfi_debug_header)) {
+			d_vpr_e("%s: invalid pkt size %d\n",
+				__func__, pkt->size);
+			continue;
+		}
+		if (pkt->size >= packet_size) {
+			d_vpr_e("%s: pkt size[%d] >= packet_size[%d]\n",
+				__func__, pkt->size, packet_size);
+			continue;
+		}
+
+		packet[pkt->size] = '\0';
+		/*
+		 * All fw messages starts with new line character. This
+		 * causes dprintk to print this message in two lines
+		 * in the kernel log. Ignoring the first character
+		 * from the message fixes this to print it in a single
+		 * line.
+		 */
+		log = (u8 *)packet + sizeof(struct hfi_debug_header) + 1;
+		dprintk_firmware(log_level_fw, "%s", log);
+	}
+
+	if (local_packet)
+		vfree(packet);
+}
+
+static int __cmdq_write(struct msm_vidc_core *core, void *pkt)
+{
+	int rc;
+
+	rc = __resume(core);
+	if (rc)
+		return rc;
+
+	rc = venus_hfi_queue_cmd_write(core, pkt);
+	if (!rc)
+		__schedule_power_collapse_work(core);
+
+	return rc;
+}
+
+static int __sys_set_debug(struct msm_vidc_core *core, u32 debug)
+{
+	int rc = 0;
+
+	rc = hfi_packet_sys_debug_config(core, core->packet,
+					 core->packet_size, debug);
+	if (rc)
+		goto exit;
+
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		goto exit;
+
+exit:
+	if (rc)
+		d_vpr_e("Debug mode setting to FW failed\n");
+
+	return rc;
+}
+
+static int __sys_set_power_control(struct msm_vidc_core *core, bool enable)
+{
+	int rc = 0;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF)) {
+		d_vpr_e("%s: skipping as power control hanfoff was not done\n",
+			__func__);
+		return rc;
+	}
+
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return rc;
+	}
+
+	rc = hfi_packet_sys_intraframe_powercollapse(core, core->packet,
+						     core->packet_size, enable);
+	if (rc)
+		return rc;
+
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_FW_PWR_CTRL, __func__);
+	if (rc)
+		return rc;
+
+	d_vpr_h("%s: set hardware power control successful\n", __func__);
+
+	return rc;
+}
+
+int __prepare_pc(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = hfi_packet_sys_pc_prep(core, core->packet, core->packet_size);
+	if (rc) {
+		d_vpr_e("Failed to create sys pc prep pkt\n");
+		goto err_pc_prep;
+	}
+
+	if (__cmdq_write(core, core->packet))
+		rc = -ENOTEMPTY;
+	if (rc)
+		d_vpr_e("Failed to prepare venus for power off");
+err_pc_prep:
+	return rc;
+}
+
+static int __power_collapse(struct msm_vidc_core *core, bool force)
+{
+	int rc = 0;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_h("%s: Power already disabled\n", __func__);
+		goto exit;
+	}
+
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: Core not in init state\n", __func__);
+		return -EINVAL;
+	}
+
+	__flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size);
+
+	rc = call_iris_op(core, prepare_pc, core);
+	if (rc)
+		goto skip_power_off;
+
+	rc = __suspend(core);
+	if (rc)
+		d_vpr_e("Failed __suspend\n");
+
+exit:
+	return rc;
+
+skip_power_off:
+	d_vpr_e("%s: skipped\n", __func__);
+	return -EAGAIN;
+}
+
+static int __release_subcaches(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct subcache_info *sinfo;
+	struct hfi_buffer buf;
+
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	if (!core->resource->subcache_set.set_to_fw) {
+		d_vpr_h("Subcaches not set to Venus\n");
+		return 0;
+	}
+
+	rc = hfi_create_header(core->packet, core->packet_size,
+			       0, core->header_id++);
+	if (rc)
+		return rc;
+
+	memset(&buf, 0, sizeof(struct hfi_buffer));
+	buf.type = HFI_BUFFER_SUBCACHE;
+	buf.flags = HFI_BUF_HOST_FLAG_RELEASE;
+
+	venus_hfi_for_each_subcache_reverse(core, sinfo) {
+		if (!sinfo->isactive)
+			continue;
+
+		buf.index = sinfo->subcache->slice_id;
+		buf.buffer_size = sinfo->subcache->slice_size;
+
+		rc = hfi_create_packet(core->packet,
+				       core->packet_size,
+				       HFI_CMD_BUFFER,
+				       HFI_BUF_HOST_FLAG_NONE,
+				       HFI_PAYLOAD_STRUCTURE,
+				       HFI_PORT_NONE,
+				       core->packet_id++,
+				       &buf,
+				       sizeof(buf));
+		if (rc)
+			return rc;
+	}
+
+	/* Set resource to Venus for activated subcaches */
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		return rc;
+
+	venus_hfi_for_each_subcache_reverse(core, sinfo) {
+		if (!sinfo->isactive)
+			continue;
+
+		d_vpr_h("%s: release Subcache id %d size %lu done\n",
+			__func__, sinfo->subcache->slice_id,
+			sinfo->subcache->slice_size);
+	}
+	core->resource->subcache_set.set_to_fw = false;
+
+	return 0;
+}
+
+static int __set_subcaches(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct subcache_info *sinfo;
+	struct hfi_buffer buf;
+
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	if (core->resource->subcache_set.set_to_fw) {
+		d_vpr_h("Subcaches already set to Venus\n");
+		return 0;
+	}
+
+	rc = hfi_create_header(core->packet, core->packet_size,
+			       0, core->header_id++);
+	if (rc)
+		goto err_fail_set_subacaches;
+
+	memset(&buf, 0, sizeof(struct hfi_buffer));
+	buf.type = HFI_BUFFER_SUBCACHE;
+	buf.flags = HFI_BUF_HOST_FLAG_NONE;
+
+	venus_hfi_for_each_subcache(core, sinfo) {
+		if (!sinfo->isactive)
+			continue;
+		buf.index = sinfo->subcache->slice_id;
+		buf.buffer_size = sinfo->subcache->slice_size;
+
+		rc = hfi_create_packet(core->packet,
+				       core->packet_size,
+				       HFI_CMD_BUFFER,
+				       HFI_BUF_HOST_FLAG_NONE,
+				       HFI_PAYLOAD_STRUCTURE,
+				       HFI_PORT_NONE,
+				       core->packet_id++,
+				       &buf,
+				       sizeof(buf));
+		if (rc)
+			goto err_fail_set_subacaches;
+	}
+
+	/* Set resource to Venus for activated subcaches */
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		goto err_fail_set_subacaches;
+
+	venus_hfi_for_each_subcache(core, sinfo) {
+		if (!sinfo->isactive)
+			continue;
+		d_vpr_h("%s: set Subcache id %d size %lu done\n",
+			__func__, sinfo->subcache->slice_id,
+			sinfo->subcache->slice_size);
+	}
+	core->resource->subcache_set.set_to_fw = true;
+
+	return 0;
+
+err_fail_set_subacaches:
+	call_res_op(core, llcc, core, false);
+	return rc;
+}
+
+static int __venus_power_off(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
+		return 0;
+
+	rc = call_iris_op(core, power_off, core);
+	if (rc) {
+		d_vpr_e("Failed to power off, err: %d\n", rc);
+		return rc;
+	}
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
+
+	return rc;
+}
+
+static int __venus_power_on(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
+		return 0;
+
+	rc = call_iris_op(core, power_on, core);
+	if (rc) {
+		d_vpr_e("Failed to power on, err: %d\n", rc);
+		return rc;
+	}
+
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+
+	return rc;
+}
+
+static int __suspend(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_h("Power already disabled\n");
+		return 0;
+	}
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	d_vpr_h("Entering suspend\n");
+
+	rc = fw_suspend(core);
+	if (rc) {
+		d_vpr_e("Failed to suspend video core %d\n", rc);
+		goto err_tzbsp_suspend;
+	}
+
+	call_res_op(core, llcc, core, false);
+
+	__venus_power_off(core);
+	d_vpr_h("Venus power off\n");
+	return rc;
+
+err_tzbsp_suspend:
+	return rc;
+}
+
+static int __resume(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		goto exit;
+	} else if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: core not in valid state\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	d_vpr_h("Resuming from power collapse\n");
+	/* reset handoff done from core sub_state */
+	rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
+	if (rc)
+		return rc;
+	/* reset hw pwr ctrl from core sub_state */
+	rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL, 0, __func__);
+	if (rc)
+		return rc;
+
+	rc = __venus_power_on(core);
+	if (rc) {
+		d_vpr_e("Failed to power on venus\n");
+		goto err_venus_power_on;
+	}
+
+	/* Reboot the firmware */
+	rc = fw_resume(core);
+	if (rc) {
+		d_vpr_e("Failed to resume video core %d\n", rc);
+		goto err_set_video_state;
+	}
+
+	/*
+	 * Hand off control of regulators to h/w _after_ loading fw.
+	 * Note that the GDSC will turn off when switching from normal
+	 * (s/w triggered) to fast (HW triggered) unless the h/w vote is
+	 * present.
+	 */
+	call_res_op(core, gdsc_hw_ctrl, core);
+
+	/* Wait for boot completion */
+	rc = call_iris_op(core, boot_firmware, core);
+	if (rc) {
+		d_vpr_e("Failed to reset venus core\n");
+		goto err_reset_core;
+	}
+
+	__sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT);
+
+	rc = call_res_op(core, llcc, core, true);
+	if (rc) {
+		d_vpr_e("Failed to activate subcache\n");
+		goto err_reset_core;
+	}
+	__set_subcaches(core);
+
+	rc = __sys_set_power_control(core, true);
+	if (rc) {
+		d_vpr_e("%s: set power control failed\n", __func__);
+		call_res_op(core, gdsc_sw_ctrl, core);
+		rc = 0;
+	}
+
+	d_vpr_h("Resumed from power collapse\n");
+exit:
+	/* Don't reset skip_pc_count for SYS_PC_PREP cmd */
+	//if (core->last_packet_type != HFI_CMD_SYS_PC_PREP)
+	//	core->skip_pc_count = 0;
+	return rc;
+err_reset_core:
+	fw_suspend(core);
+err_set_video_state:
+	__venus_power_off(core);
+err_venus_power_on:
+	d_vpr_e("Failed to resume from power collapse\n");
+	return rc;
+}
+
+int __load_fw(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	/* clear all substates */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
+
+	rc = __venus_power_on(core);
+	if (rc) {
+		d_vpr_e("%s: power on failed\n", __func__);
+		goto fail_power;
+	}
+
+	rc = fw_load(core);
+	if (rc)
+		goto fail_load_fw;
+
+	/*
+	 * Hand off control of regulators to h/w _after_ loading fw.
+	 * Note that the GDSC will turn off when switching from normal
+	 * (s/w triggered) to fast (HW triggered) unless the h/w vote is
+	 * present.
+	 */
+	call_res_op(core, gdsc_hw_ctrl, core);
+
+	return rc;
+fail_load_fw:
+	__venus_power_off(core);
+fail_power:
+	return rc;
+}
+
+void __unload_fw(struct msm_vidc_core *core)
+{
+	if (!core->resource->fw_cookie)
+		return;
+
+	cancel_delayed_work(&core->pm_work);
+	fw_unload(core);
+	__venus_power_off(core);
+
+	/* clear all substates */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
+}
+
+static int __response_handler(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (call_iris_op(core, watchdog, core, core->intr_status)) {
+		struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT};
+
+		core_lock(core, __func__);
+		msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__);
+		/* mark cpu watchdog error */
+		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_CPU_WATCHDOG, __func__);
+		d_vpr_e("%s: CPU WD error received\n", __func__);
+		core_unlock(core, __func__);
+
+		return handle_system_error(core, &pkt);
+	}
+
+	memset(core->response_packet, 0, core->packet_size);
+	while (!venus_hfi_queue_msg_read(core, core->response_packet)) {
+		rc = handle_response(core, core->response_packet);
+		if (rc)
+			continue;
+		/* check for system error */
+		if (core->state != MSM_VIDC_CORE_INIT)
+			break;
+		memset(core->response_packet, 0, core->packet_size);
+	}
+
+	__schedule_power_collapse_work(core);
+	__flush_debug_queue(core, core->response_packet, core->packet_size);
+
+	return rc;
+}
+
+irqreturn_t venus_hfi_isr(int irq, void *data)
+{
+	disable_irq_nosync(irq);
+	return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t venus_hfi_isr_handler(int irq, void *data)
+{
+	struct msm_vidc_core *core = data;
+	int num_responses = 0, rc = 0;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return IRQ_NONE;
+	}
+
+	core_lock(core, __func__);
+	rc = __resume(core);
+	if (rc) {
+		d_vpr_e("%s: Power on failed\n", __func__);
+		core_unlock(core, __func__);
+		goto exit;
+	}
+	call_iris_op(core, clear_interrupt, core);
+	core_unlock(core, __func__);
+
+	num_responses = __response_handler(core);
+
+exit:
+	if (!call_iris_op(core, watchdog, core, core->intr_status))
+		enable_irq(irq);
+
+	return IRQ_HANDLED;
+}
+
+void venus_hfi_pm_work_handler(struct work_struct *work)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = container_of(work, struct msm_vidc_core, pm_work.work);
+
+	core_lock(core, __func__);
+	d_vpr_h("%s: try power collapse\n", __func__);
+	/*
+	 * It is ok to check this variable outside the lock since
+	 * it is being updated in this context only
+	 */
+	if (core->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) {
+		d_vpr_e("Failed to PC for %d times\n",
+			core->skip_pc_count);
+		core->skip_pc_count = 0;
+		msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__);
+		/* mark video hw unresponsive */
+		msm_vidc_change_core_sub_state(core, 0,
+					       CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__);
+		/* do core deinit to handle error */
+		msm_vidc_core_deinit_locked(core, true);
+		goto unlock;
+	}
+
+	/* core already deinited - skip power collapse */
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		goto unlock;
+	}
+
+	rc = __power_collapse(core, false);
+	switch (rc) {
+	case 0:
+		core->skip_pc_count = 0;
+		/* Cancel pending delayed works if any */
+		__cancel_power_collapse_work(core);
+		d_vpr_h("%s: power collapse successful!\n", __func__);
+		break;
+	case -EBUSY:
+		core->skip_pc_count = 0;
+		d_vpr_h("%s: retry PC as dsp is busy\n", __func__);
+		__schedule_power_collapse_work(core);
+		break;
+	case -EAGAIN:
+		core->skip_pc_count++;
+		d_vpr_e("%s: retry power collapse (count %d)\n",
+			__func__, core->skip_pc_count);
+		__schedule_power_collapse_work(core);
+		break;
+	default:
+		d_vpr_e("%s: power collapse failed\n", __func__);
+		break;
+	}
+unlock:
+	core_unlock(core, __func__);
+}
+
+static int __sys_init(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc =  hfi_packet_sys_init(core, core->packet, core->packet_size);
+	if (rc)
+		return rc;
+
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int __sys_image_version(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = hfi_packet_image_version(core, core->packet, core->packet_size);
+	if (rc)
+		return rc;
+
+	rc = __cmdq_write(core, core->packet);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int venus_hfi_core_init(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	d_vpr_h("%s(): core %pK\n", __func__, core);
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	rc = venus_hfi_queue_init(core);
+	if (rc)
+		goto error;
+
+	rc = __load_fw(core);
+	if (rc)
+		goto error;
+
+	rc = call_iris_op(core, boot_firmware, core);
+	if (rc)
+		goto error;
+
+	rc = call_res_op(core, llcc, core, true);
+	if (rc)
+		goto error;
+
+	rc = __sys_init(core);
+	if (rc)
+		goto error;
+
+	rc = __sys_image_version(core);
+	if (rc)
+		goto error;
+
+	rc = __sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT);
+	if (rc)
+		goto error;
+
+	rc = __set_subcaches(core);
+	if (rc)
+		goto error;
+
+	rc = __sys_set_power_control(core, true);
+	if (rc) {
+		d_vpr_e("%s: set power control failed\n", __func__);
+		call_res_op(core, gdsc_sw_ctrl, core);
+		rc = 0;
+	}
+
+	d_vpr_h("%s(): successful\n", __func__);
+	return 0;
+
+error:
+	d_vpr_e("%s(): failed\n", __func__);
+	return rc;
+}
+
+int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force)
+{
+	int rc = 0;
+
+	d_vpr_h("%s(): core %pK\n", __func__, core);
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
+		return 0;
+	__resume(core);
+	__flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size);
+	__release_subcaches(core);
+	call_res_op(core, llcc, core, false);
+	__unload_fw(core);
+	/**
+	 * coredump need to be called after firmware unload, coredump also
+	 * copying queues memory. So need to be called before queues deinit.
+	 */
+	if (msm_vidc_fw_dump)
+		fw_coredump(core);
+
+	return 0;
+}
+
+int venus_hfi_suspend(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!core->capabilities[SW_PC].value) {
+		d_vpr_h("Skip suspending venus\n");
+		return 0;
+	}
+
+	d_vpr_h("Suspending Venus\n");
+	rc = __power_collapse(core, true);
+	if (!rc) {
+		/* Cancel pending delayed works if any */
+		__cancel_power_collapse_work(core);
+	} else {
+		d_vpr_e("%s: Venus is busy\n", __func__);
+		rc = -EBUSY;
+	}
+
+	return rc;
+}
+
+int venus_hfi_session_open(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	__sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT);
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_OPEN,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED),
+					HFI_PORT_NONE,
+					0, /* session_id */
+					HFI_PAYLOAD_U32,
+					&inst->session_id, /* payload */
+					sizeof(u32));
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_set_codec(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 codec;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id, core->header_id++);
+	if (rc)
+		goto unlock;
+
+	codec = get_hfi_codec(inst);
+	rc = hfi_create_packet(inst->packet, inst->packet_size,
+			       HFI_PROP_CODEC,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32_ENUM,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &codec,
+			       sizeof(u32));
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_property(struct msm_vidc_inst *inst,
+			       u32 pkt_type, u32 flags, u32 port,
+			       u32 payload_type, void *payload, u32 payload_size)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id, core->header_id++);
+	if (rc)
+		goto unlock;
+	rc = hfi_create_packet(inst->packet, inst->packet_size,
+			       pkt_type,
+			       flags,
+			       payload_type,
+			       port,
+			       core->packet_id++,
+			       payload,
+			       payload_size);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_close(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_CLOSE,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED |
+					HFI_HOST_FLAGS_NON_DISCARDABLE),
+					HFI_PORT_NONE,
+					inst->session_id,
+					HFI_PAYLOAD_NONE,
+					NULL,
+					0);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_START,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED),
+					get_hfi_port(inst, port),
+					inst->session_id,
+					HFI_PAYLOAD_NONE,
+					NULL,
+					0);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_STOP,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED |
+					HFI_HOST_FLAGS_NON_DISCARDABLE),
+					get_hfi_port(inst, port),
+					inst->session_id,
+					HFI_PAYLOAD_NONE,
+					NULL,
+					0);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_PAUSE,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED),
+					get_hfi_port(inst, port),
+					inst->session_id,
+					HFI_PAYLOAD_NONE,
+					NULL,
+					0);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_resume(struct msm_vidc_inst *inst,
+			     enum msm_vidc_port_type port, u32 payload)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_RESUME,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED),
+					get_hfi_port(inst, port),
+					inst->session_id,
+					HFI_PAYLOAD_U32,
+					&payload,
+					sizeof(u32));
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	if (port != INPUT_PORT) {
+		i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
+		goto unlock;
+	}
+
+	rc = hfi_packet_session_command(inst,
+					HFI_CMD_DRAIN,
+					(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+					HFI_HOST_FLAGS_INTR_REQUIRED |
+					HFI_HOST_FLAGS_NON_DISCARDABLE),
+					get_hfi_port(inst, port),
+					inst->session_id,
+					HFI_PAYLOAD_NONE,
+					NULL,
+					0);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_session_command(struct msm_vidc_inst *inst,
+			      u32 cmd, enum msm_vidc_port_type port, u32 payload_type,
+			      void *payload, u32 payload_size)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id,
+			core->header_id++);
+	if (rc)
+		goto unlock;
+
+	rc = hfi_create_packet(inst->packet, inst->packet_size,
+			       cmd,
+			       (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+			       HFI_HOST_FLAGS_INTR_REQUIRED),
+			       payload_type,
+			       get_hfi_port(inst, port),
+			       core->packet_id++,
+			       payload,
+			       payload_size);
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_queue_buffer(struct msm_vidc_inst *inst,
+			   struct msm_vidc_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_buffer hfi_buffer;
+
+	if (!inst->packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = get_hfi_buffer(inst, buffer, &hfi_buffer);
+	if (rc)
+		goto unlock;
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id, core->header_id++);
+	if (rc)
+		goto unlock;
+
+	rc = hfi_create_packet(inst->packet,
+			       inst->packet_size,
+			       HFI_CMD_BUFFER,
+			       HFI_HOST_FLAGS_INTR_REQUIRED,
+			       HFI_PAYLOAD_STRUCTURE,
+			       get_hfi_port_from_buffer_type(inst, buffer->type),
+			       core->packet_id++,
+			       &hfi_buffer,
+			       sizeof(hfi_buffer));
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_release_buffer(struct msm_vidc_inst *inst,
+			     struct msm_vidc_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_buffer hfi_buffer;
+
+	if (!inst->packet || !buffer) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	core_lock(core, __func__);
+
+	if (!__valdiate_session(core, inst, __func__)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	rc = get_hfi_buffer(inst, buffer, &hfi_buffer);
+	if (rc)
+		goto unlock;
+
+	/* add release flag */
+	hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE;
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id, core->header_id++);
+	if (rc)
+		goto unlock;
+
+	rc = hfi_create_packet(inst->packet,
+			       inst->packet_size,
+			       HFI_CMD_BUFFER,
+			       (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+			       HFI_HOST_FLAGS_INTR_REQUIRED),
+			       HFI_PAYLOAD_STRUCTURE,
+			       get_hfi_port_from_buffer_type(inst, buffer->type),
+			       core->packet_id++,
+			       &hfi_buffer,
+			       sizeof(hfi_buffer));
+	if (rc)
+		goto unlock;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc)
+		goto unlock;
+
+unlock:
+	core_unlock(core, __func__);
+	return rc;
+}
+
+int venus_hfi_scale_clocks(struct msm_vidc_inst *inst, u64 freq)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	rc = __resume(core);
+	if (rc) {
+		i_vpr_e(inst, "%s: Resume from power collapse failed\n", __func__);
+		goto exit;
+	}
+	rc = call_res_op(core, set_clks, core, freq);
+	if (rc)
+		goto exit;
+
+exit:
+	core_unlock(core, __func__);
+
+	return rc;
+}
+
+int venus_hfi_scale_buses(struct msm_vidc_inst *inst, u64 bw_ddr, u64 bw_llcc)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+	rc = __resume(core);
+	if (rc) {
+		i_vpr_e(inst, "%s: Resume from power collapse failed\n", __func__);
+		goto exit;
+	}
+	rc = call_res_op(core, set_bw, core, bw_ddr, bw_llcc);
+	if (rc)
+		goto exit;
+
+exit:
+	core_unlock(core, __func__);
+
+	return rc;
+}
+
+int venus_hfi_set_ir_period(struct msm_vidc_inst *inst, u32 ir_type,
+			    enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 ir_period, sync_frame_req = 0;
+
+	core = inst->core;
+
+	core_lock(core, __func__);
+
+	ir_period = inst->capabilities[cap_id].value;
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       inst->session_id, core->header_id++);
+	if (rc)
+		goto exit;
+
+	/* Request sync frame if ir period enabled dynamically */
+	if (!inst->ir_enabled) {
+		inst->ir_enabled = ((ir_period > 0) ? true : false);
+		if (inst->ir_enabled && inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+			sync_frame_req = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR;
+			rc = hfi_create_packet(inst->packet, inst->packet_size,
+					       HFI_PROP_REQUEST_SYNC_FRAME,
+					       HFI_HOST_FLAGS_NONE,
+					       HFI_PAYLOAD_U32_ENUM,
+					       msm_vidc_get_port_info(inst, REQUEST_I_FRAME),
+					       core->packet_id++,
+					       &sync_frame_req,
+					       sizeof(u32));
+			if (rc)
+				goto exit;
+		}
+	}
+
+	rc = hfi_create_packet(inst->packet, inst->packet_size,
+			       ir_type,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       msm_vidc_get_port_info(inst, cap_id),
+			       core->packet_id++,
+			       &ir_period,
+			       sizeof(u32));
+	if (rc)
+		goto exit;
+
+	rc = __cmdq_write(inst->core, inst->packet);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to set inst->capabilities[%d] %s to fw\n",
+			__func__, cap_id, cap_name(cap_id));
+		goto exit;
+	}
+
+exit:
+	core_unlock(core, __func__);
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 19/33] iris: vidc: hfi: add Host Firmware Interface (HFI) response handling
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (17 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI) Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues Vikash Garodia
                   ` (16 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements the handlng of responses sent from firmware to the
host driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../qcom/iris/vidc/inc/venus_hfi_response.h        |   26 +
 .../qcom/iris/vidc/src/venus_hfi_response.c        | 1607 ++++++++++++++++++++
 2 files changed, 1633 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
new file mode 100644
index 0000000..92e6c0e
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __VENUS_HFI_RESPONSE_H__
+#define __VENUS_HFI_RESPONSE_H__
+
+#include "hfi_packet.h"
+
+extern struct msm_vidc_core *g_core;
+int handle_response(struct msm_vidc_core *core,
+		    void *response);
+int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+		    u32 core_resp_pkt_size, const char *func);
+bool is_valid_port(struct msm_vidc_inst *inst, u32 port,
+		   const char *func);
+bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
+			      u32 buffer_type, const char *func);
+int handle_system_error(struct msm_vidc_core *core,
+			struct hfi_packet *pkt);
+int handle_release_output_buffer(struct msm_vidc_inst *inst,
+				 struct hfi_buffer *buffer);
+
+#endif // __VENUS_HFI_RESPONSE_H__
diff --git a/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c
new file mode 100644
index 0000000..b12a564
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c
@@ -0,0 +1,1607 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/of_address.h>
+
+#include "hfi_packet.h"
+#include "msm_vdec.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "venus_hfi.h"
+#include "venus_hfi_response.h"
+
+#define in_range(range, val) (((range.begin) < (val)) && ((range.end) > (val)))
+
+struct msm_vidc_core_hfi_range {
+	u32 begin;
+	u32 end;
+	int (*handle)(struct msm_vidc_core *core, struct hfi_packet *pkt);
+};
+
+struct msm_vidc_inst_hfi_range {
+	u32 begin;
+	u32 end;
+	int (*handle)(struct msm_vidc_inst *inst, struct hfi_packet *pkt);
+};
+
+struct msm_vidc_hfi_buffer_handle {
+	enum hfi_buffer_type type;
+	int (*handle)(struct msm_vidc_inst *inst, struct hfi_buffer *buffer);
+};
+
+struct msm_vidc_hfi_packet_handle {
+	enum hfi_buffer_type type;
+	int (*handle)(struct msm_vidc_inst *inst, struct hfi_packet *pkt);
+};
+
+void print_psc_properties(const char *str, struct msm_vidc_inst *inst,
+			  struct msm_vidc_subscription_params subsc_params)
+{
+	i_vpr_h(inst,
+		"%s: w %d, h %d, crop: offsets[0] %#x offsets[1] %#x, bit depth %#x, coded frames %d, fw min count %d, poc %d, color info %d, profile %d, level %d, tier %d\n",
+		str, (subsc_params.bitstream_resolution & HFI_BITMASK_BITSTREAM_WIDTH) >> 16,
+		(subsc_params.bitstream_resolution & HFI_BITMASK_BITSTREAM_HEIGHT),
+		subsc_params.crop_offsets[0], subsc_params.crop_offsets[1],
+		subsc_params.bit_depth, subsc_params.coded_frames,
+		subsc_params.fw_min_count, subsc_params.pic_order_cnt,
+		subsc_params.color_info, subsc_params.profile, subsc_params.level,
+		subsc_params.tier);
+}
+
+static void print_sfr_message(struct msm_vidc_core *core)
+{
+	struct msm_vidc_sfr *vsfr = NULL;
+	u32 vsfr_size = 0;
+	void *p = NULL;
+
+	vsfr = (struct msm_vidc_sfr *)core->sfr.align_virtual_addr;
+	if (vsfr) {
+		if (vsfr->bufsize != core->sfr.mem_size) {
+			d_vpr_e("Invalid SFR buf size %d actual %d\n",
+				vsfr->bufsize, core->sfr.mem_size);
+			return;
+		}
+		vsfr_size = vsfr->bufsize - sizeof(u32);
+		p = memchr(vsfr->rg_data, '\0', vsfr_size);
+	/* SFR isn't guaranteed to be NULL terminated */
+		if (!p)
+			vsfr->rg_data[vsfr_size - 1] = '\0';
+
+		d_vpr_e(FMT_STRING_MSG_SFR, vsfr->rg_data);
+	}
+}
+
+u32 vidc_port_from_hfi(struct msm_vidc_inst *inst,
+		       enum hfi_packet_port_type hfi_port)
+{
+	enum msm_vidc_port_type port = MAX_PORT;
+
+	if (is_decode_session(inst)) {
+		switch (hfi_port) {
+		case HFI_PORT_BITSTREAM:
+			port = INPUT_PORT;
+			break;
+		case HFI_PORT_RAW:
+			port = OUTPUT_PORT;
+			break;
+		case HFI_PORT_NONE:
+			port = PORT_NONE;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid hfi port type %d\n",
+				__func__, hfi_port);
+			break;
+		}
+	} else if (is_encode_session(inst)) {
+		switch (hfi_port) {
+		case HFI_PORT_RAW:
+			port = INPUT_PORT;
+			break;
+		case HFI_PORT_BITSTREAM:
+			port = OUTPUT_PORT;
+			break;
+		case HFI_PORT_NONE:
+			port = PORT_NONE;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid hfi port type %d\n",
+				__func__, hfi_port);
+			break;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %#x\n",
+			__func__, inst->domain);
+	}
+
+	return port;
+}
+
+bool is_valid_hfi_port(struct msm_vidc_inst *inst, u32 port,
+		       u32 buffer_type, const char *func)
+{
+	if (port == HFI_PORT_NONE &&
+	    buffer_type != HFI_BUFFER_ARP &&
+		buffer_type != HFI_BUFFER_PERSIST)
+		goto invalid;
+
+	if (port != HFI_PORT_BITSTREAM && port != HFI_PORT_RAW)
+		goto invalid;
+
+	return true;
+
+invalid:
+	i_vpr_e(inst, "%s: invalid port %#x buffer_type %u\n",
+		func, port, buffer_type);
+	return false;
+}
+
+bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
+			      u32 buffer_type, const char *func)
+{
+	if (buffer_type != HFI_BUFFER_BITSTREAM &&
+	    buffer_type != HFI_BUFFER_RAW &&
+	    buffer_type != HFI_BUFFER_BIN &&
+	    buffer_type != HFI_BUFFER_ARP &&
+	    buffer_type != HFI_BUFFER_COMV &&
+	    buffer_type != HFI_BUFFER_NON_COMV &&
+	    buffer_type != HFI_BUFFER_LINE &&
+	    buffer_type != HFI_BUFFER_DPB &&
+	    buffer_type != HFI_BUFFER_PERSIST &&
+	    buffer_type != HFI_BUFFER_VPSS) {
+		i_vpr_e(inst, "%s: invalid buffer type %#x\n",
+			func, buffer_type);
+		return false;
+	}
+	return true;
+}
+
+int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+		    u32 core_resp_pkt_size, const char *func)
+{
+	u8 *response_limit;
+	u32 response_pkt_size = 0;
+
+	if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size) {
+		d_vpr_e("%s: invalid params\n", func);
+		return -EINVAL;
+	}
+
+	response_limit = core_resp_pkt + core_resp_pkt_size;
+
+	if (response_pkt < core_resp_pkt || response_pkt > response_limit) {
+		d_vpr_e("%s: invalid packet address\n", func);
+		return -EINVAL;
+	}
+
+	response_pkt_size = *(u32 *)response_pkt;
+	if (!response_pkt_size) {
+		d_vpr_e("%s: response packet size cannot be zero\n", func);
+		return -EINVAL;
+	}
+
+	if (response_pkt_size < sizeof(struct hfi_packet)) {
+		d_vpr_e("%s: invalid packet size %d\n",
+			func, response_pkt_size);
+		return -EINVAL;
+	}
+
+	if (response_pkt + response_pkt_size > response_limit) {
+		d_vpr_e("%s: invalid packet size %d\n",
+			func, response_pkt_size);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int validate_hdr_packet(struct msm_vidc_core *core,
+			       struct hfi_header *hdr, const char *function)
+{
+	struct hfi_packet *packet;
+	u8 *pkt;
+	int i, rc = 0;
+
+	if (hdr->size < sizeof(struct hfi_header) + sizeof(struct hfi_packet)) {
+		d_vpr_e("%s: invalid header size %d\n", __func__, hdr->size);
+		return -EINVAL;
+	}
+
+	pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header));
+
+	/* validate all packets */
+	for (i = 0; i < hdr->num_packets; i++) {
+		packet = (struct hfi_packet *)pkt;
+		rc = validate_packet(pkt, core->response_packet, core->packet_size, function);
+		if (rc)
+			return rc;
+
+		pkt += packet->size;
+	}
+
+	return 0;
+}
+
+static bool check_for_packet_payload(struct msm_vidc_inst *inst,
+				     struct hfi_packet *pkt, const char *func)
+{
+	u32 payload_size = 0;
+
+	if (pkt->payload_info == HFI_PAYLOAD_NONE) {
+		i_vpr_h(inst, "%s: no playload available for packet %#x\n",
+			func, pkt->type);
+		return false;
+	}
+
+	switch (pkt->payload_info) {
+	case HFI_PAYLOAD_U32:
+	case HFI_PAYLOAD_S32:
+	case HFI_PAYLOAD_Q16:
+	case HFI_PAYLOAD_U32_ENUM:
+	case HFI_PAYLOAD_32_PACKED:
+		payload_size = 4;
+		break;
+	case HFI_PAYLOAD_U64:
+	case HFI_PAYLOAD_S64:
+	case HFI_PAYLOAD_64_PACKED:
+		payload_size = 8;
+		break;
+	case HFI_PAYLOAD_STRUCTURE:
+		if (pkt->type == HFI_CMD_BUFFER)
+			payload_size = sizeof(struct hfi_buffer);
+		break;
+	default:
+		payload_size = 0;
+		break;
+	}
+
+	if (pkt->size < sizeof(struct hfi_packet) + payload_size) {
+		i_vpr_e(inst,
+			"%s: invalid payload size %u payload type %#x for packet %#x\n",
+			func, pkt->size, pkt->payload_info, pkt->type);
+		return false;
+	}
+
+	return true;
+}
+
+static int handle_session_last_flag_info(struct msm_vidc_inst *inst,
+					 struct hfi_packet *pkt)
+{
+	int rc = 0;
+
+	if (pkt->type == HFI_INFO_HFI_FLAG_PSC_LAST) {
+		if (msm_vidc_allow_psc_last_flag(inst))
+			rc = msm_vidc_process_psc_last_flag(inst);
+		else
+			rc = -EINVAL;
+	} else if (pkt->type == HFI_INFO_HFI_FLAG_DRAIN_LAST) {
+		if (msm_vidc_allow_drain_last_flag(inst))
+			rc = msm_vidc_process_drain_last_flag(inst);
+		else
+			rc = -EINVAL;
+	} else {
+		i_vpr_e(inst, "%s: invalid packet type %#x\n", __func__,
+			pkt->type);
+	}
+
+	if (rc)
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+
+	return rc;
+}
+
+static int handle_session_info(struct msm_vidc_inst *inst,
+			       struct hfi_packet *pkt)
+{
+	int rc = 0;
+	char *info;
+
+	switch (pkt->type) {
+	case HFI_INFO_UNSUPPORTED:
+		info = "unsupported";
+		break;
+	case HFI_INFO_DATA_CORRUPT:
+		info = "data corrupt";
+		inst->hfi_frame_info.data_corrupt = 1;
+		break;
+	case HFI_INFO_BUFFER_OVERFLOW:
+		info = "buffer overflow";
+		inst->hfi_frame_info.overflow = 1;
+		break;
+	case HFI_INFO_HFI_FLAG_DRAIN_LAST:
+		info = "drain last flag";
+		rc = handle_session_last_flag_info(inst, pkt);
+		break;
+	case HFI_INFO_HFI_FLAG_PSC_LAST:
+		info = "drc last flag";
+		rc = handle_session_last_flag_info(inst, pkt);
+		break;
+	default:
+		info = "unknown";
+		break;
+	}
+
+	i_vpr_h(inst, "session info (%#x): %s\n", pkt->type, info);
+
+	return rc;
+}
+
+static int handle_session_error(struct msm_vidc_inst *inst,
+				struct hfi_packet *pkt)
+{
+	int rc = 0;
+	char *error;
+
+	switch (pkt->type) {
+	case HFI_ERROR_MAX_SESSIONS:
+		error = "exceeded max sessions";
+		break;
+	case HFI_ERROR_UNKNOWN_SESSION:
+		error = "unknown session id";
+		break;
+	case HFI_ERROR_INVALID_STATE:
+		error = "invalid operation for current state";
+		break;
+	case HFI_ERROR_INSUFFICIENT_RESOURCES:
+		error = "insufficient resources";
+		break;
+	case HFI_ERROR_BUFFER_NOT_SET:
+		error = "internal buffers not set";
+		break;
+	case HFI_ERROR_FATAL:
+		error = "fatal error";
+		break;
+	default:
+		error = "unknown";
+		break;
+	}
+
+	i_vpr_e(inst, "%s: session error received %#x: %s\n",
+		__func__, pkt->type, error);
+
+	rc = msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	return rc;
+}
+
+int handle_system_error(struct msm_vidc_core *core,
+			struct hfi_packet *pkt)
+{
+	d_vpr_e("%s: system error received\n", __func__);
+	print_sfr_message(core);
+
+	msm_vidc_core_deinit(core, true);
+
+	return 0;
+}
+
+static int handle_system_init(struct msm_vidc_core *core,
+			      struct hfi_packet *pkt)
+{
+	if (!(pkt->flags & HFI_FW_FLAGS_SUCCESS)) {
+		d_vpr_h("%s: unhandled. flags=%d\n", __func__, pkt->flags);
+		return 0;
+	}
+
+	core_lock(core, __func__);
+	if (pkt->packet_id != core->sys_init_id) {
+		d_vpr_e("%s: invalid pkt id %u, expected %u\n", __func__,
+			pkt->packet_id, core->sys_init_id);
+		goto unlock;
+	}
+
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__);
+	d_vpr_h("%s: successful\n", __func__);
+
+unlock:
+	core_unlock(core, __func__);
+	return 0;
+}
+
+static int handle_session_open(struct msm_vidc_inst *inst,
+			       struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+
+	return 0;
+}
+
+static int handle_session_close(struct msm_vidc_inst *inst,
+				struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+
+	signal_session_msg_receipt(inst, SIGNAL_CMD_CLOSE);
+	return 0;
+}
+
+static int handle_session_start(struct msm_vidc_inst *inst,
+				struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful for port %d\n",
+			__func__, pkt->port);
+	return 0;
+}
+
+static int handle_session_stop(struct msm_vidc_inst *inst,
+			       struct hfi_packet *pkt)
+{
+	int rc = 0;
+	enum signal_session_response signal_type = -1;
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful for port %d\n",
+			__func__, pkt->port);
+
+	if (is_encode_session(inst)) {
+		if (pkt->port == HFI_PORT_RAW) {
+			signal_type = SIGNAL_CMD_STOP_INPUT;
+		} else if (pkt->port == HFI_PORT_BITSTREAM) {
+			signal_type = SIGNAL_CMD_STOP_OUTPUT;
+		} else {
+			i_vpr_e(inst, "%s: invalid port: %d\n",
+				__func__, pkt->port);
+			return -EINVAL;
+		}
+	} else if (is_decode_session(inst)) {
+		if (pkt->port == HFI_PORT_RAW) {
+			signal_type = SIGNAL_CMD_STOP_OUTPUT;
+		} else if (pkt->port == HFI_PORT_BITSTREAM) {
+			signal_type = SIGNAL_CMD_STOP_INPUT;
+		} else {
+			i_vpr_e(inst, "%s: invalid port: %d\n",
+				__func__, pkt->port);
+			return -EINVAL;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid session\n", __func__);
+		return -EINVAL;
+	}
+
+	if (signal_type != -1) {
+		rc = msm_vidc_process_stop_done(inst, signal_type);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int handle_session_drain(struct msm_vidc_inst *inst,
+				struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+
+	return msm_vidc_process_drain_done(inst);
+}
+
+static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags)
+{
+	u32 driver_flags = 0;
+
+	if (inst->hfi_frame_info.picture_type & HFI_PICTURE_IDR)
+		driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME;
+	else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_P)
+		driver_flags |= MSM_VIDC_BUF_FLAG_PFRAME;
+	else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_B)
+		driver_flags |= MSM_VIDC_BUF_FLAG_BFRAME;
+	else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_I)
+		driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME;
+	else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_CRA)
+		driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME;
+	else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_BLA)
+		driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME;
+
+	if (inst->hfi_frame_info.data_corrupt)
+		driver_flags |= MSM_VIDC_BUF_FLAG_ERROR;
+
+	if (inst->hfi_frame_info.overflow)
+		driver_flags |= MSM_VIDC_BUF_FLAG_ERROR;
+
+	if ((is_encode_session(inst) &&
+	     (hfi_flags & HFI_BUF_FW_FLAG_LAST)) ||
+	    (is_decode_session(inst) &&
+	    ((hfi_flags & HFI_BUF_FW_FLAG_LAST) ||
+	    (hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST))))
+		driver_flags |= MSM_VIDC_BUF_FLAG_LAST;
+
+	return driver_flags;
+}
+
+static int handle_read_only_buffer(struct msm_vidc_inst *inst,
+				   struct msm_vidc_buffer *buf)
+{
+	struct msm_vidc_buffer *ro_buf;
+	struct msm_vidc_core *core;
+	bool found = false;
+
+	core = inst->core;
+
+	if (!is_decode_session(inst) || !is_output_buffer(buf->type))
+		return 0;
+
+	if (!(buf->attr & MSM_VIDC_ATTR_READ_ONLY))
+		return 0;
+
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		if (ro_buf->device_addr == buf->device_addr) {
+			found = true;
+			break;
+		}
+	}
+	/*
+	 * RO flag: add to read_only list if buffer is not present
+	 *          if present, do nothing
+	 */
+	if (!found) {
+		ro_buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER);
+		if (!ro_buf) {
+			i_vpr_e(inst, "%s: buffer alloc failed\n", __func__);
+			return -ENOMEM;
+		}
+		ro_buf->index = -1;
+		ro_buf->inst = inst;
+		ro_buf->type = buf->type;
+		ro_buf->fd = buf->fd;
+		ro_buf->dmabuf = buf->dmabuf;
+		ro_buf->device_addr = buf->device_addr;
+		ro_buf->data_offset = buf->data_offset;
+		ro_buf->dbuf_get = buf->dbuf_get;
+		buf->dbuf_get = 0;
+		INIT_LIST_HEAD(&ro_buf->list);
+		list_add_tail(&ro_buf->list, &inst->buffers.read_only.list);
+		print_vidc_buffer(VIDC_LOW, "low ", "ro buf added", inst, ro_buf);
+	} else {
+		print_vidc_buffer(VIDC_LOW, "low ", "ro buf found", inst, ro_buf);
+	}
+	ro_buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
+
+	return 0;
+}
+
+static int handle_non_read_only_buffer(struct msm_vidc_inst *inst,
+				       struct hfi_buffer *buffer)
+{
+	struct msm_vidc_buffer *ro_buf;
+
+	if (!is_decode_session(inst) || buffer->type != HFI_BUFFER_RAW)
+		return 0;
+
+	if (buffer->flags & HFI_BUF_FW_FLAG_READONLY)
+		return 0;
+
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		if (ro_buf->device_addr == buffer->base_address) {
+			ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int handle_psc_last_flag_buffer(struct msm_vidc_inst *inst,
+				       struct hfi_buffer *buffer)
+{
+	if (!(buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST))
+		return 0;
+
+	if (!msm_vidc_allow_psc_last_flag(inst))
+		return -EINVAL;
+
+	return msm_vidc_process_psc_last_flag(inst);
+}
+
+static int handle_drain_last_flag_buffer(struct msm_vidc_inst *inst,
+					 struct hfi_buffer *buffer)
+{
+	int rc = 0;
+
+	if (!(buffer->flags & HFI_BUF_FW_FLAG_LAST))
+		return 0;
+
+	if (!msm_vidc_allow_drain_last_flag(inst))
+		return -EINVAL;
+
+	if (is_decode_session(inst)) {
+		rc = msm_vidc_process_drain_last_flag(inst);
+		if (rc)
+			return rc;
+	} else if (is_encode_session(inst)) {
+		rc = msm_vidc_state_change_drain_last_flag(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int handle_input_buffer(struct msm_vidc_inst *inst,
+			       struct hfi_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	struct msm_vidc_core *core;
+	bool found;
+
+	core = inst->core;
+	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_INPUT, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	found = false;
+	list_for_each_entry(buf, &buffers->list, list) {
+		if (buf->index == buffer->index) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		i_vpr_e(inst, "%s: invalid buffer idx %d addr %#llx data_offset %d\n",
+			__func__, buffer->index, buffer->base_address,
+			buffer->data_offset);
+		return -EINVAL;
+	}
+
+	if (!(buf->attr & MSM_VIDC_ATTR_QUEUED)) {
+		print_vidc_buffer(VIDC_ERR, "err ", "not queued", inst, buf);
+		return 0;
+	}
+
+	buf->data_size = buffer->data_size;
+	buf->attr &= ~MSM_VIDC_ATTR_QUEUED;
+	buf->attr |= MSM_VIDC_ATTR_DEQUEUED;
+
+	buf->flags = 0;
+	buf->flags = get_driver_buffer_flags(inst, buffer->flags);
+
+	print_vidc_buffer(VIDC_HIGH, "high", "dqbuf", inst, buf);
+	msm_vidc_update_stats(inst, buf, MSM_VIDC_DEBUGFS_EVENT_EBD);
+
+	return rc;
+}
+
+static int handle_output_buffer(struct msm_vidc_inst *inst,
+				struct hfi_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	struct msm_vidc_core *core;
+	bool found, fatal = false;
+
+	core = inst->core;
+
+	/* handle drain last flag buffer */
+	if (buffer->flags & HFI_BUF_FW_FLAG_LAST) {
+		rc = handle_drain_last_flag_buffer(inst, buffer);
+		if (rc)
+			msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+
+	if (is_decode_session(inst)) {
+		/* handle release response for decoder output buffer */
+		if (buffer->flags & HFI_BUF_FW_FLAG_RELEASE_DONE)
+			return handle_release_output_buffer(inst, buffer);
+		/* handle psc last flag buffer */
+		if (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) {
+			rc = handle_psc_last_flag_buffer(inst, buffer);
+			if (rc)
+				msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+		/* handle non-read only buffer */
+		if (!(buffer->flags & HFI_BUF_FW_FLAG_READONLY)) {
+			rc = handle_non_read_only_buffer(inst, buffer);
+			if (rc)
+				msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+	}
+
+	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	found = false;
+	list_for_each_entry(buf, &buffers->list, list) {
+		if (!(buf->attr & MSM_VIDC_ATTR_QUEUED))
+			continue;
+		if (is_decode_session(inst))
+			found = (buf->index == buffer->index &&
+				buf->device_addr == buffer->base_address &&
+				buf->data_offset == buffer->data_offset);
+		else
+			found = (buf->index == buffer->index);
+
+		if (found)
+			break;
+	}
+	if (!found) {
+		i_vpr_l(inst, "%s: invalid idx %d daddr %#llx\n",
+			__func__, buffer->index, buffer->base_address);
+		return 0;
+	}
+
+	buf->data_offset = buffer->data_offset;
+	buf->data_size = buffer->data_size;
+	buf->timestamp = buffer->timestamp;
+
+	buf->attr &= ~MSM_VIDC_ATTR_QUEUED;
+	buf->attr |= MSM_VIDC_ATTR_DEQUEUED;
+
+	if (is_encode_session(inst)) {
+		/* encoder output is not expected to be corrupted */
+		if (inst->hfi_frame_info.data_corrupt) {
+			i_vpr_e(inst, "%s: encode output is corrupted\n", __func__);
+			fatal = true;
+		}
+		if (inst->hfi_frame_info.overflow) {
+			/* overflow not expected for cbr_cfr session */
+			if (!buffer->data_size && inst->hfi_rc_type == HFI_RC_CBR_CFR) {
+				i_vpr_e(inst, "%s: overflow detected for cbr_cfr session\n",
+					__func__);
+				fatal = true;
+			}
+		}
+		if (fatal)
+			msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+
+	/*
+	 * reset data size to zero for last flag buffer.
+	 * reset RO flag for last flag buffer.
+	 */
+	if ((buffer->flags & HFI_BUF_FW_FLAG_LAST) ||
+	    (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)) {
+		if (buffer->data_size) {
+			i_vpr_e(inst, "%s: reset data size to zero for last flag buffer\n",
+				__func__);
+			buf->data_size = 0;
+		}
+		if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) {
+			i_vpr_e(inst, "%s: reset RO flag for last flag buffer\n",
+				__func__);
+			buffer->flags &= ~HFI_BUF_FW_FLAG_READONLY;
+		}
+	}
+
+	if (is_decode_session(inst)) {
+		/* RO flag is not expected when internal dpb buffers are allocated */
+		if (inst->buffers.dpb.size && buffer->flags & HFI_BUF_FW_FLAG_READONLY) {
+			print_vidc_buffer(VIDC_ERR, "err ", "unexpected RO flag", inst, buf);
+			msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+
+		if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) {
+			buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
+			rc = handle_read_only_buffer(inst, buf);
+			if (rc)
+				msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		} else {
+			buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
+		}
+	}
+
+	buf->flags = 0;
+	buf->flags = get_driver_buffer_flags(inst, buffer->flags);
+
+	if (is_decode_session(inst)) {
+		inst->power.fw_cr = inst->hfi_frame_info.cr;
+		inst->power.fw_cf = inst->hfi_frame_info.cf;
+	} else {
+		inst->power.fw_cr = inst->hfi_frame_info.cr;
+	}
+
+	if (is_decode_session(inst) && buf->data_size)
+		msm_vidc_update_timestamp_rate(inst, buf->timestamp);
+
+	print_vidc_buffer(VIDC_HIGH, "high", "dqbuf", inst, buf);
+	msm_vidc_update_stats(inst, buf, MSM_VIDC_DEBUGFS_EVENT_FBD);
+
+	return rc;
+}
+
+static int handle_dequeue_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int i;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	struct msm_vidc_buffer *dummy;
+	struct msm_vidc_core *core;
+	static const enum msm_vidc_buffer_type buffer_type[] = {
+		MSM_VIDC_BUF_INPUT,
+		MSM_VIDC_BUF_OUTPUT,
+	};
+
+	core = inst->core;
+	for (i = 0; i < ARRAY_SIZE(buffer_type); i++) {
+		buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__);
+		if (!buffers)
+			return -EINVAL;
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			if (buf->attr & MSM_VIDC_ATTR_DEQUEUED) {
+				buf->attr &= ~MSM_VIDC_ATTR_DEQUEUED;
+				/*
+				 * do not send vb2_buffer_done when fw returns
+				 * same buffer again
+				 */
+				if (buf->attr & MSM_VIDC_ATTR_BUFFER_DONE) {
+					print_vidc_buffer(VIDC_HIGH, "high",
+							  "vb2 done already",
+							  inst, buf);
+				} else {
+					buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE;
+					if (buf->dbuf_get) {
+						call_mem_op(core, dma_buf_put, inst, buf->dmabuf);
+						buf->dbuf_get = 0;
+					}
+					rc = msm_vidc_vb2_buffer_done(inst, buf);
+					if (rc) {
+						print_vidc_buffer(VIDC_HIGH, "err ",
+								  "vb2 done failed",
+								  inst, buf);
+						/* ignore the error */
+						rc = 0;
+					}
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int handle_release_internal_buffer(struct msm_vidc_inst *inst,
+					  struct hfi_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf;
+	bool found;
+
+	buffers = msm_vidc_get_buffers(inst, hfi_buf_type_to_driver(inst->domain, buffer->type,
+								    HFI_PORT_NONE), __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	found = false;
+	list_for_each_entry(buf, &buffers->list, list) {
+		if (buf->device_addr == buffer->base_address) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		i_vpr_e(inst, "%s: invalid idx %d daddr %#llx\n",
+			__func__, buffer->index, buffer->base_address);
+		return -EINVAL;
+	}
+
+	if (!is_internal_buffer(buf->type))
+		return 0;
+
+	/* remove QUEUED attribute */
+	buf->attr &= ~MSM_VIDC_ATTR_QUEUED;
+
+	/*
+	 * firmware will return/release internal buffer in two cases
+	 * - driver sent release cmd in which case driver should destroy the buffer
+	 * - as part stop cmd in which case driver can reuse the buffer, so skip
+	 *   destroying the buffer
+	 */
+	if (buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) {
+		rc = msm_vidc_destroy_internal_buffer(inst, buf);
+		if (rc)
+			return rc;
+	}
+	return rc;
+}
+
+int handle_release_output_buffer(struct msm_vidc_inst *inst,
+				 struct hfi_buffer *buffer)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *buf;
+	bool found = false;
+
+	list_for_each_entry(buf, &inst->buffers.read_only.list, list) {
+		if (buf->device_addr == buffer->base_address &&
+		    buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		i_vpr_e(inst, "%s: invalid idx %d daddr %#llx\n",
+			__func__, buffer->index, buffer->base_address);
+		return -EINVAL;
+	}
+
+	buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
+	buf->attr &= ~MSM_VIDC_ATTR_PENDING_RELEASE;
+	print_vidc_buffer(VIDC_LOW, "low ", "release done", inst, buf);
+
+	return rc;
+}
+
+static int handle_session_buffer(struct msm_vidc_inst *inst,
+				 struct hfi_packet *pkt)
+{
+	int i, rc = 0;
+	struct hfi_buffer *buffer;
+	u32 hfi_handle_size = 0;
+	const struct msm_vidc_hfi_buffer_handle *hfi_handle_arr = NULL;
+	static const struct msm_vidc_hfi_buffer_handle enc_input_hfi_handle[] = {
+		{HFI_BUFFER_RAW,            handle_input_buffer               },
+		{HFI_BUFFER_VPSS,           handle_release_internal_buffer    },
+	};
+	static const struct msm_vidc_hfi_buffer_handle enc_output_hfi_handle[] = {
+		{HFI_BUFFER_BITSTREAM,      handle_output_buffer              },
+		{HFI_BUFFER_BIN,            handle_release_internal_buffer    },
+		{HFI_BUFFER_COMV,           handle_release_internal_buffer    },
+		{HFI_BUFFER_NON_COMV,       handle_release_internal_buffer    },
+		{HFI_BUFFER_LINE,           handle_release_internal_buffer    },
+		{HFI_BUFFER_ARP,            handle_release_internal_buffer    },
+		{HFI_BUFFER_DPB,            handle_release_internal_buffer    },
+	};
+	static const struct msm_vidc_hfi_buffer_handle dec_input_hfi_handle[] = {
+		{HFI_BUFFER_BITSTREAM,      handle_input_buffer               },
+		{HFI_BUFFER_BIN,            handle_release_internal_buffer    },
+		{HFI_BUFFER_COMV,           handle_release_internal_buffer    },
+		{HFI_BUFFER_NON_COMV,       handle_release_internal_buffer    },
+		{HFI_BUFFER_LINE,           handle_release_internal_buffer    },
+		{HFI_BUFFER_PERSIST,        handle_release_internal_buffer    },
+	};
+	static const struct msm_vidc_hfi_buffer_handle dec_output_hfi_handle[] = {
+		{HFI_BUFFER_RAW,            handle_output_buffer              },
+		{HFI_BUFFER_DPB,            handle_release_internal_buffer    },
+	};
+
+	if (pkt->payload_info == HFI_PAYLOAD_NONE) {
+		i_vpr_h(inst, "%s: received hfi buffer packet without payload\n",
+			__func__);
+		return 0;
+	}
+
+	if (!check_for_packet_payload(inst, pkt, __func__)) {
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
+	}
+
+	buffer = (struct hfi_buffer *)((u8 *)pkt + sizeof(struct hfi_packet));
+	if (!is_valid_hfi_buffer_type(inst, buffer->type, __func__)) {
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
+	}
+
+	if (!is_valid_hfi_port(inst, pkt->port, buffer->type, __func__)) {
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
+	}
+
+	if (is_encode_session(inst)) {
+		if (pkt->port == HFI_PORT_RAW) {
+			hfi_handle_size = ARRAY_SIZE(enc_input_hfi_handle);
+			hfi_handle_arr = enc_input_hfi_handle;
+		} else if (pkt->port == HFI_PORT_BITSTREAM) {
+			hfi_handle_size = ARRAY_SIZE(enc_output_hfi_handle);
+			hfi_handle_arr = enc_output_hfi_handle;
+		}
+	} else if (is_decode_session(inst)) {
+		if (pkt->port == HFI_PORT_BITSTREAM) {
+			hfi_handle_size = ARRAY_SIZE(dec_input_hfi_handle);
+			hfi_handle_arr = dec_input_hfi_handle;
+		} else if (pkt->port == HFI_PORT_RAW) {
+			hfi_handle_size = ARRAY_SIZE(dec_output_hfi_handle);
+			hfi_handle_arr = dec_output_hfi_handle;
+		}
+	}
+
+	/* handle invalid session */
+	if (!hfi_handle_arr || !hfi_handle_size) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+
+	/* handle session buffer */
+	for (i = 0; i < hfi_handle_size; i++) {
+		if (hfi_handle_arr[i].type == buffer->type) {
+			rc = hfi_handle_arr[i].handle(inst, buffer);
+			if (rc)
+				return rc;
+			break;
+		}
+	}
+
+	/* handle unknown buffer type */
+	if (i == hfi_handle_size) {
+		i_vpr_e(inst, "%s: port %u, unknown buffer type %#x\n", __func__,
+			pkt->port, buffer->type);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int handle_input_port_settings_change(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+
+	allow = msm_vidc_allow_input_psc(inst);
+	if (allow == MSM_VIDC_DISALLOW) {
+		return -EINVAL;
+	} else if (allow == MSM_VIDC_ALLOW) {
+		rc = msm_vidc_state_change_input_psc(inst);
+		if (rc)
+			return rc;
+		print_psc_properties("INPUT_PSC", inst, inst->subcr_params[INPUT_PORT]);
+		rc = msm_vdec_input_port_settings_change(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int handle_output_port_settings_change(struct msm_vidc_inst *inst)
+{
+	print_psc_properties("OUTPUT_PSC", inst, inst->subcr_params[OUTPUT_PORT]);
+
+	return 0;
+}
+
+static int handle_port_settings_change(struct msm_vidc_inst *inst,
+				       struct hfi_packet *pkt)
+{
+	int rc = 0;
+
+	i_vpr_h(inst, "%s: Received port settings change, type %d\n",
+		__func__, pkt->port);
+
+	if (pkt->port == HFI_PORT_RAW) {
+		rc = handle_output_port_settings_change(inst);
+		if (rc)
+			goto exit;
+	} else if (pkt->port == HFI_PORT_BITSTREAM) {
+		rc = handle_input_port_settings_change(inst);
+		if (rc)
+			goto exit;
+	} else {
+		i_vpr_e(inst, "%s: invalid port type: %#x\n",
+			__func__, pkt->port);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	if (rc)
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+	return rc;
+}
+
+static int handle_session_subscribe_mode(struct msm_vidc_inst *inst,
+					 struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+	return 0;
+}
+
+static int handle_session_pause(struct msm_vidc_inst *inst,
+				struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+	return 0;
+}
+
+static int handle_session_resume(struct msm_vidc_inst *inst,
+				 struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		i_vpr_h(inst, "%s: successful\n", __func__);
+	return 0;
+}
+
+static int handle_session_command(struct msm_vidc_inst *inst,
+				  struct hfi_packet *pkt)
+{
+	int i, rc;
+	static const struct msm_vidc_hfi_packet_handle hfi_pkt_handle[] = {
+		{HFI_CMD_OPEN,              handle_session_open               },
+		{HFI_CMD_CLOSE,             handle_session_close              },
+		{HFI_CMD_START,             handle_session_start              },
+		{HFI_CMD_STOP,              handle_session_stop               },
+		{HFI_CMD_DRAIN,             handle_session_drain              },
+		{HFI_CMD_BUFFER,            handle_session_buffer             },
+		{HFI_CMD_SETTINGS_CHANGE,   handle_port_settings_change       },
+		{HFI_CMD_SUBSCRIBE_MODE,    handle_session_subscribe_mode     },
+		{HFI_CMD_PAUSE,             handle_session_pause              },
+		{HFI_CMD_RESUME,            handle_session_resume             },
+	};
+
+	/* handle session pkt */
+	for (i = 0; i < ARRAY_SIZE(hfi_pkt_handle); i++) {
+		if (hfi_pkt_handle[i].type == pkt->type) {
+			rc = hfi_pkt_handle[i].handle(inst, pkt);
+			if (rc)
+				return rc;
+			break;
+		}
+	}
+
+	/* handle unknown buffer type */
+	if (i == ARRAY_SIZE(hfi_pkt_handle)) {
+		i_vpr_e(inst, "%s: Unsupported command type: %#x\n", __func__, pkt->type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int handle_dpb_list_property(struct msm_vidc_inst *inst,
+				    struct hfi_packet *pkt)
+{
+	u32 payload_size, num_words_in_payload;
+	u8 *payload_start;
+	int i = 0;
+	struct msm_vidc_buffer *ro_buf;
+	bool found = false;
+	u64 device_addr;
+
+	if (!is_decode_session(inst)) {
+		i_vpr_e(inst,
+			"%s: unsupported for non-decode session\n", __func__);
+		return -EINVAL;
+	}
+
+	payload_size = pkt->size - sizeof(struct hfi_packet);
+	num_words_in_payload = payload_size / 4;
+	payload_start = (u8 *)((u8 *)pkt + sizeof(struct hfi_packet));
+	memset(inst->dpb_list_payload, 0, MAX_DPB_LIST_ARRAY_SIZE);
+
+	if (payload_size > MAX_DPB_LIST_PAYLOAD_SIZE) {
+		i_vpr_e(inst,
+			"%s: dpb list payload size %d exceeds expected max size %d\n",
+			__func__, payload_size, MAX_DPB_LIST_PAYLOAD_SIZE);
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		return -EINVAL;
+	}
+	memcpy(inst->dpb_list_payload, payload_start, payload_size);
+
+	/*
+	 * dpb_list_payload details:
+	 * payload[0-1]           : 64 bits base_address of DPB-1
+	 * payload[2]             : 32 bits addr_offset  of DPB-1
+	 * payload[3]             : 32 bits data_offset  of DPB-1
+	 */
+	for (i = 0; (i + 3) < num_words_in_payload; i = i + 4) {
+		i_vpr_l(inst,
+			"%s: base addr %#x %#x, addr offset %#x, data offset %#x\n",
+			__func__, inst->dpb_list_payload[i], inst->dpb_list_payload[i + 1],
+			inst->dpb_list_payload[i + 2], inst->dpb_list_payload[i + 3]);
+	}
+
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		found = false;
+		/* do not mark RELEASE_ELIGIBLE for non-read only buffers */
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY))
+			continue;
+		/* no need to mark RELEASE_ELIGIBLE again */
+		if (ro_buf->attr & MSM_VIDC_ATTR_RELEASE_ELIGIBLE)
+			continue;
+		/*
+		 * do not add RELEASE_ELIGIBLE to buffers for which driver
+		 * sent release cmd already
+		 */
+		if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+			continue;
+		for (i = 0; (i + 3) < num_words_in_payload; i = i + 4) {
+			device_addr = *((u64 *)(&inst->dpb_list_payload[i]));
+			if (ro_buf->device_addr == device_addr) {
+				found = true;
+				break;
+			}
+		}
+		/* mark a buffer as RELEASE_ELIGIBLE if not found in dpb list */
+		if (!found)
+			ro_buf->attr |= MSM_VIDC_ATTR_RELEASE_ELIGIBLE;
+	}
+
+	return 0;
+}
+
+static int handle_property_with_payload(struct msm_vidc_inst *inst,
+					struct hfi_packet *pkt, u32 port)
+{
+	int rc = 0;
+	u32 *payload_ptr = NULL;
+
+	payload_ptr = (u32 *)((u8 *)pkt + sizeof(struct hfi_packet));
+	if (!payload_ptr) {
+		i_vpr_e(inst,
+			"%s: payload_ptr cannot be null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (pkt->type) {
+	case HFI_PROP_BITSTREAM_RESOLUTION:
+		inst->subcr_params[port].bitstream_resolution = payload_ptr[0];
+		break;
+	case HFI_PROP_CROP_OFFSETS:
+		inst->subcr_params[port].crop_offsets[0] = payload_ptr[0];
+		inst->subcr_params[port].crop_offsets[1] = payload_ptr[1];
+		break;
+	case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
+		inst->subcr_params[port].bit_depth = payload_ptr[0];
+		break;
+	case HFI_PROP_CODED_FRAMES:
+		inst->subcr_params[port].coded_frames = payload_ptr[0];
+		break;
+	case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
+		inst->subcr_params[port].fw_min_count = payload_ptr[0];
+		break;
+	case HFI_PROP_PIC_ORDER_CNT_TYPE:
+		inst->subcr_params[port].pic_order_cnt = payload_ptr[0];
+		break;
+	case HFI_PROP_SIGNAL_COLOR_INFO:
+		inst->subcr_params[port].color_info = payload_ptr[0];
+		break;
+	case HFI_PROP_PROFILE:
+		inst->subcr_params[port].profile = payload_ptr[0];
+		break;
+	case HFI_PROP_LEVEL:
+		inst->subcr_params[port].level = payload_ptr[0];
+		break;
+	case HFI_PROP_TIER:
+		inst->subcr_params[port].tier = payload_ptr[0];
+		break;
+	case HFI_PROP_PICTURE_TYPE:
+		inst->hfi_frame_info.picture_type = payload_ptr[0];
+		if (inst->hfi_frame_info.picture_type & HFI_PICTURE_B)
+			inst->has_bframe = true;
+		if (inst->hfi_frame_info.picture_type & HFI_PICTURE_IDR)
+			inst->iframe = true;
+		else
+			inst->iframe = false;
+		break;
+	case HFI_PROP_SUBFRAME_INPUT:
+		if (port != INPUT_PORT) {
+			i_vpr_e(inst,
+				"%s: invalid port: %d for property %#x\n",
+				__func__, pkt->port, pkt->type);
+			break;
+		}
+		inst->hfi_frame_info.subframe_input = 1;
+		break;
+	case HFI_PROP_WORST_COMPRESSION_RATIO:
+		inst->hfi_frame_info.cr = payload_ptr[0];
+		break;
+	case HFI_PROP_WORST_COMPLEXITY_FACTOR:
+		inst->hfi_frame_info.cf = payload_ptr[0];
+		break;
+	case HFI_PROP_CABAC_SESSION:
+		if (payload_ptr[0] == 1)
+			msm_vidc_update_cap_value(inst, ENTROPY_MODE,
+						  V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+						  __func__);
+		else
+			msm_vidc_update_cap_value(inst, ENTROPY_MODE,
+						  V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+						  __func__);
+		break;
+	case HFI_PROP_DPB_LIST:
+		rc = handle_dpb_list_property(inst, pkt);
+		if (rc)
+			break;
+		break;
+	case HFI_PROP_QUALITY_MODE:
+		if (inst->capabilities[QUALITY_MODE].value !=  payload_ptr[0])
+			i_vpr_e(inst,
+				"%s: fw quality mode(%d) not matching the capability value(%d)\n",
+				__func__,  payload_ptr[0],
+				inst->capabilities[QUALITY_MODE].value);
+		break;
+	case HFI_PROP_STAGE:
+		if (inst->capabilities[STAGE].value !=  payload_ptr[0])
+			i_vpr_e(inst,
+				"%s: fw stage mode(%d) not matching the capability value(%d)\n",
+				__func__,  payload_ptr[0], inst->capabilities[STAGE].value);
+		break;
+	case HFI_PROP_PIPE:
+		if (inst->capabilities[PIPE].value !=  payload_ptr[0])
+			i_vpr_e(inst,
+				"%s: fw pipe mode(%d) not matching the capability value(%d)\n",
+				__func__,  payload_ptr[0], inst->capabilities[PIPE].value);
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid property %#x\n",
+			__func__, pkt->type);
+		break;
+	}
+
+	return rc;
+}
+
+static int handle_property_without_payload(struct msm_vidc_inst *inst,
+					   struct hfi_packet *pkt, u32 port)
+{
+	int rc = 0;
+
+	switch (pkt->type) {
+	case HFI_PROP_DPB_LIST:
+		/*
+		 * if fw sends dpb list property without payload,
+		 * it means there are no more reference buffers.
+		 */
+		rc = handle_dpb_list_property(inst, pkt);
+		if (rc)
+			break;
+		break;
+	case HFI_PROP_NO_OUTPUT:
+		if (port != INPUT_PORT) {
+			i_vpr_e(inst,
+				"%s: invalid port: %d for property %#x\n",
+				__func__, pkt->port, pkt->type);
+			break;
+		}
+		i_vpr_h(inst, "received no_output property\n");
+		inst->hfi_frame_info.no_output = 1;
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid property %#x\n",
+			__func__, pkt->type);
+		break;
+	}
+
+	return rc;
+}
+
+static int handle_session_property(struct msm_vidc_inst *inst,
+				   struct hfi_packet *pkt)
+{
+	int rc = 0;
+	u32 port;
+
+	i_vpr_l(inst, "%s: property type %#x\n", __func__, pkt->type);
+
+	port = vidc_port_from_hfi(inst, pkt->port);
+	if (port >= MAX_PORT) {
+		i_vpr_e(inst,
+			"%s: invalid port: %d for property %#x\n",
+			__func__, pkt->port, pkt->type);
+		return -EINVAL;
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_INFORMATION) {
+		i_vpr_h(inst,
+			"%s: information flag received for property %#x packet\n",
+			__func__, pkt->type);
+		return 0;
+	}
+
+	if (check_for_packet_payload(inst, pkt, __func__)) {
+		rc = handle_property_with_payload(inst, pkt, port);
+		if (rc)
+			return rc;
+	} else {
+		rc = handle_property_without_payload(inst, pkt, port);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+static int handle_image_version_property(struct msm_vidc_core *core,
+					 struct hfi_packet *pkt)
+{
+	u32 i = 0;
+	u8 *str_image_version;
+	u32 req_bytes;
+
+	req_bytes = pkt->size - sizeof(*pkt);
+	if (req_bytes < VENUS_VERSION_LENGTH - 1) {
+		d_vpr_e("%s: bad_pkt: %d\n", __func__, req_bytes);
+		return -EINVAL;
+	}
+	str_image_version = (u8 *)pkt + sizeof(struct hfi_packet);
+	/*
+	 * 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 < VENUS_VERSION_LENGTH - 1; i++) {
+		if (str_image_version[i] != '\0')
+			core->fw_version[i] = str_image_version[i];
+		else
+			core->fw_version[i] = ' ';
+	}
+	core->fw_version[i] = '\0';
+
+	d_vpr_h("%s: F/W version: %s\n", __func__, core->fw_version);
+	return 0;
+}
+
+static int handle_system_property(struct msm_vidc_core *core,
+				  struct hfi_packet *pkt)
+{
+	int rc = 0;
+
+	switch (pkt->type) {
+	case HFI_PROP_IMAGE_VERSION:
+		rc = handle_image_version_property(core, pkt);
+		break;
+	default:
+		d_vpr_h("%s: property type %#x successful\n",
+			__func__, pkt->type);
+		break;
+	}
+	return rc;
+}
+
+static int handle_system_response(struct msm_vidc_core *core,
+				  struct hfi_header *hdr)
+{
+	int rc = 0;
+	struct hfi_packet *packet;
+	u8 *pkt, *start_pkt;
+	int i, j;
+	static const struct msm_vidc_core_hfi_range be[] = {
+		{HFI_SYSTEM_ERROR_BEGIN,   HFI_SYSTEM_ERROR_END,   handle_system_error     },
+		{HFI_PROP_BEGIN,           HFI_PROP_END,           handle_system_property  },
+		{HFI_CMD_BEGIN,            HFI_CMD_END,            handle_system_init      },
+	};
+
+	start_pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header));
+	for (i = 0; i < ARRAY_SIZE(be); i++) {
+		pkt = start_pkt;
+		for (j = 0; j < hdr->num_packets; j++) {
+			packet = (struct hfi_packet *)pkt;
+			/* handle system error */
+			if (packet->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
+				d_vpr_e("%s: received system error %#x\n",
+					__func__, packet->type);
+				rc = handle_system_error(core, packet);
+				if (rc)
+					goto exit;
+				goto exit;
+			}
+			if (in_range(be[i], packet->type)) {
+				rc = be[i].handle(core, packet);
+				if (rc)
+					goto exit;
+
+				/* skip processing anymore packets after system error */
+				if (!i) {
+					d_vpr_e("%s: skip processing anymore packets\n", __func__);
+					goto exit;
+				}
+			}
+			pkt += packet->size;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int __handle_session_response(struct msm_vidc_inst *inst,
+				     struct hfi_header *hdr)
+{
+	int rc = 0;
+	struct hfi_packet *packet;
+	u8 *pkt, *start_pkt;
+	bool dequeue = false;
+	int i, j;
+	static const struct msm_vidc_inst_hfi_range be[] = {
+		{HFI_SESSION_ERROR_BEGIN,  HFI_SESSION_ERROR_END,  handle_session_error    },
+		{HFI_INFORMATION_BEGIN,    HFI_INFORMATION_END,    handle_session_info     },
+		{HFI_PROP_BEGIN,           HFI_PROP_END,           handle_session_property },
+		{HFI_CMD_BEGIN,            HFI_CMD_END,            handle_session_command  },
+	};
+
+	memset(&inst->hfi_frame_info, 0, sizeof(struct msm_vidc_hfi_frame_info));
+	start_pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header));
+	for (i = 0; i < ARRAY_SIZE(be); i++) {
+		pkt = start_pkt;
+		for (j = 0; j < hdr->num_packets; j++) {
+			packet = (struct hfi_packet *)pkt;
+			/* handle session error */
+			if (packet->flags & HFI_FW_FLAGS_SESSION_ERROR) {
+				i_vpr_e(inst, "%s: received session error %#x\n",
+					__func__, packet->type);
+				handle_session_error(inst, packet);
+			}
+			if (in_range(be[i], packet->type)) {
+				dequeue |= (packet->type == HFI_CMD_BUFFER);
+				rc = be[i].handle(inst, packet);
+				if (rc)
+					msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+			}
+			pkt += packet->size;
+		}
+	}
+
+	if (dequeue) {
+		rc = handle_dequeue_buffers(inst);
+		if (rc)
+			return rc;
+	}
+	memset(&inst->hfi_frame_info, 0, sizeof(struct msm_vidc_hfi_frame_info));
+
+	return rc;
+}
+
+static int handle_session_response(struct msm_vidc_core *core,
+				   struct hfi_header *hdr)
+{
+	struct msm_vidc_inst *inst;
+	struct hfi_packet *packet;
+	u8 *pkt;
+	int i, rc = 0;
+	bool found_ipsc = false;
+
+	inst = get_inst(core, hdr->session_id);
+	if (!inst) {
+		d_vpr_e("%s: Invalid inst\n", __func__);
+		return -EINVAL;
+	}
+
+	inst_lock(inst, __func__);
+	/* search for cmd settings change pkt */
+	pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header));
+	for (i = 0; i < hdr->num_packets; i++) {
+		packet = (struct hfi_packet *)pkt;
+		if (packet->type == HFI_CMD_SETTINGS_CHANGE) {
+			if (packet->port == HFI_PORT_BITSTREAM) {
+				found_ipsc = true;
+				break;
+			}
+		}
+		pkt += packet->size;
+	}
+
+	/* if ipsc packet is found, initialise subsc_params */
+	if (found_ipsc)
+		msm_vdec_init_input_subcr_params(inst);
+
+	rc = __handle_session_response(inst, hdr);
+	if (rc)
+		goto exit;
+
+exit:
+	inst_unlock(inst, __func__);
+	put_inst(inst);
+	return rc;
+}
+
+int handle_response(struct msm_vidc_core *core, void *response)
+{
+	struct hfi_header *hdr;
+	int rc = 0;
+
+	hdr = (struct hfi_header *)response;
+	rc = validate_hdr_packet(core, hdr, __func__);
+	if (rc) {
+		d_vpr_e("%s: hdr pkt validation failed\n", __func__);
+		return handle_system_error(core, NULL);
+	}
+
+	if (!hdr->session_id)
+		return handle_system_response(core, hdr);
+	else
+		return handle_session_response(core, hdr);
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (18 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 19/33] iris: vidc: hfi: add Host Firmware Interface (HFI) response handling Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 17:58   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 21/33] iris: vidc: hfi: Add packetization layer Vikash Garodia
                   ` (15 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements functions to allocate and update the shared memory
used for sending commands to firmware and receiving messages from
firmware.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |  89 ++++
 .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  | 537 +++++++++++++++++++++
 2 files changed, 626 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
new file mode 100644
index 0000000..f533811
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VENUS_HFI_QUEUE_H_
+#define _VENUS_HFI_QUEUE_H_
+
+#include <linux/types.h>
+
+#include "msm_vidc_internal.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		0
+#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q		1
+#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q		2
+#define HFI_MASK_QHDR_STATUS			0x000000ff
+
+#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
+
+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;
+	void *device_addr;
+	char name[256];
+};
+
+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;
+};
+
+#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)
+#define TOTAL_QSIZE	(SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE)
+
+int venus_hfi_queue_cmd_write(struct msm_vidc_core *core, void *pkt);
+int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt);
+int venus_hfi_queue_dbg_read(struct msm_vidc_core *core, void *pkt);
+void venus_hfi_queue_deinit(struct msm_vidc_core *core);
+int venus_hfi_queue_init(struct msm_vidc_core *core);
+int venus_hfi_reset_queue_header(struct msm_vidc_core *core);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
new file mode 100644
index 0000000..8e038ba
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "venus_hfi.h"
+#include "venus_hfi_queue.h"
+
+static void __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 __dump_packet(u8 *packet, const char *function, void *qinfo)
+{
+	u32 c = 0, session_id, 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 * 32];
+
+	session_id = *((u32 *)packet + 1);
+
+	d_vpr_t("%08x: %s: %pK\n", session_id, function, qinfo);
+
+	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);
+		d_vpr_t("%08x: %s\n", session_id, row);
+	}
+}
+
+static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
+			 bool *rx_req_is_set)
+{
+	struct hfi_queue_header *queue;
+	u32 packet_size_in_words, new_write_idx;
+	u32 empty_space, read_idx, write_idx;
+	u32 *write_ptr;
+
+	if (!qinfo || !packet) {
+		d_vpr_e("%s: invalid params %pK %pK\n",
+			__func__, qinfo, packet);
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		d_vpr_e("Queues have already been freed\n");
+		return -EINVAL;
+	}
+
+	queue = (struct hfi_queue_header *)qinfo->q_hdr;
+	if (!queue) {
+		d_vpr_e("queue not present\n");
+		return -ENOENT;
+	}
+
+	if (msm_vidc_debug & VIDC_PKT)
+		__dump_packet(packet, __func__, qinfo);
+
+	packet_size_in_words = (*(u32 *)packet) >> 2;
+	if (!packet_size_in_words || packet_size_in_words >
+		qinfo->q_array.mem_size >> 2) {
+		d_vpr_e("Invalid packet size\n");
+		return -ENODATA;
+	}
+
+	read_idx = queue->qhdr_read_idx;
+	write_idx = queue->qhdr_write_idx;
+
+	empty_space = (write_idx >=  read_idx) ?
+		((qinfo->q_array.mem_size >> 2) - (write_idx -  read_idx)) :
+		(read_idx - write_idx);
+	if (empty_space <= packet_size_in_words) {
+		queue->qhdr_tx_req =  1;
+		d_vpr_e("Insufficient size (%d) to write (%d)\n",
+			empty_space, packet_size_in_words);
+		return -ENOTEMPTY;
+	}
+
+	queue->qhdr_tx_req =  0;
+
+	new_write_idx = write_idx + packet_size_in_words;
+	write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+			(write_idx << 2));
+	if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+	    write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+	    qinfo->q_array.mem_size)) {
+		d_vpr_e("Invalid write index\n");
+		return -ENODATA;
+	}
+
+	if (new_write_idx < (qinfo->q_array.mem_size >> 2)) {
+		memcpy(write_ptr, packet, packet_size_in_words << 2);
+	} else {
+		new_write_idx -= qinfo->q_array.mem_size >> 2;
+		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;
+	if (rx_req_is_set)
+		*rx_req_is_set = true;
+	/*
+	 * Memory barrier to make sure write index is updated before an
+	 * interrupt is raised on venus.
+	 */
+	mb();
+	return 0;
+}
+
+static int __read_queue(struct msm_vidc_iface_q_info *qinfo, 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;
+	u32 read_idx, write_idx;
+	int rc = 0;
+
+	if (!qinfo || !packet || !pb_tx_req_is_set) {
+		d_vpr_e("%s: invalid params %pK %pK %pK\n",
+			__func__, qinfo, packet, pb_tx_req_is_set);
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		d_vpr_e("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) {
+		d_vpr_e("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;
+
+	read_idx = queue->qhdr_read_idx;
+	write_idx = queue->qhdr_write_idx;
+
+	if (read_idx == write_idx) {
+		queue->qhdr_rx_req = receive_request;
+		/*
+		 * mb() to ensure qhdr is updated in main memory
+		 * so that venus reads the updated header values
+		 */
+		mb();
+		*pb_tx_req_is_set = 0;
+		d_vpr_l("%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) +
+				(read_idx << 2));
+	if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+	    read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+	    qinfo->q_array.mem_size - sizeof(*read_ptr))) {
+		d_vpr_e("Invalid read index\n");
+		return -ENODATA;
+	}
+
+	packet_size_in_words = (*read_ptr) >> 2;
+	if (!packet_size_in_words) {
+		d_vpr_e("Zero packet size\n");
+		return -ENODATA;
+	}
+
+	new_read_idx = read_idx + packet_size_in_words;
+	if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) &&
+	    read_idx <= (qinfo->q_array.mem_size >> 2)) {
+		if (new_read_idx < (qinfo->q_array.mem_size >> 2)) {
+			memcpy(packet, read_ptr,
+			       packet_size_in_words << 2);
+		} else {
+			new_read_idx -= (qinfo->q_array.mem_size >> 2);
+			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 {
+		d_vpr_e("BAD packet received, read_idx: %#x, pkt_size: %d\n",
+			read_idx, packet_size_in_words << 2);
+		d_vpr_e("Dropping this packet\n");
+		new_read_idx = write_idx;
+		rc = -ENODATA;
+	}
+
+	queue->qhdr_rx_req = receive_request;
+
+	queue->qhdr_read_idx = new_read_idx;
+	/*
+	 * mb() to ensure qhdr is updated in main memory
+	 * so that venus reads the updated header values
+	 */
+	mb();
+
+	*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
+
+	if ((msm_vidc_debug & VIDC_PKT) &&
+	    !(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) {
+		__dump_packet(packet, __func__, qinfo);
+	}
+
+	return rc;
+}
+
+/* Writes into cmdq without raising an interrupt */
+static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core,
+				      void *pkt, bool *requires_interrupt)
+{
+	struct msm_vidc_iface_q_info *q_info;
+	int rc = -E2BIG;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto err_q_null;
+	}
+
+	q_info = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	if (!q_info) {
+		d_vpr_e("cannot write to shared Q's\n");
+		goto err_q_null;
+	}
+
+	if (!q_info->q_array.align_virtual_addr) {
+		d_vpr_e("cannot write to shared CMD Q's\n");
+		rc = -ENODATA;
+		goto err_q_null;
+	}
+
+	if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt))
+		rc = 0;
+	else
+		d_vpr_e("queue full\n");
+
+err_q_null:
+	return rc;
+}
+
+int venus_hfi_queue_cmd_write(struct msm_vidc_core *core, void *pkt)
+{
+	bool needs_interrupt = false;
+	int rc = __iface_cmdq_write_relaxed(core, pkt, &needs_interrupt);
+
+	if (!rc && needs_interrupt)
+		call_iris_op(core, raise_interrupt, core);
+
+	return rc;
+}
+
+int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct msm_vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto read_error_null;
+	}
+
+	q_info = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	if (!q_info->q_array.align_virtual_addr) {
+		d_vpr_e("cannot read from shared MSG Q's\n");
+		rc = -ENODATA;
+		goto read_error_null;
+	}
+
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		if (tx_req_is_set) {
+			//call_iris_op(core, raise_interrupt, core);
+			d_vpr_e("%s: queue is full\n", __func__);
+			rc = -EINVAL;
+			goto read_error_null;
+		}
+		rc = 0;
+	} else {
+		rc = -ENODATA;
+	}
+
+read_error_null:
+	return rc;
+}
+
+int venus_hfi_queue_dbg_read(struct msm_vidc_core *core, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct msm_vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	q_info = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	if (!q_info->q_array.align_virtual_addr) {
+		d_vpr_e("cannot read from shared DBG Q's\n");
+		rc = -ENODATA;
+		goto dbg_error_null;
+	}
+
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		if (tx_req_is_set) {
+			d_vpr_e("%s: queue is full\n", __func__);
+			//call_iris_op(core, raise_interrupt, core);
+			rc = -EINVAL;
+			goto dbg_error_null;
+		}
+		rc = 0;
+	} else {
+		rc = -ENODATA;
+	}
+
+dbg_error_null:
+	return rc;
+}
+
+void venus_hfi_queue_deinit(struct msm_vidc_core *core)
+{
+	int i;
+
+	if (!core->iface_q_table.align_virtual_addr) {
+		d_vpr_h("%s: queues already deallocated\n", __func__);
+		return;
+	}
+
+	call_mem_op(core, memory_unmap_free, core, &core->iface_q_table.mem);
+	call_mem_op(core, memory_unmap_free, core, &core->sfr.mem);
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		core->iface_queues[i].q_hdr = NULL;
+		core->iface_queues[i].q_array.align_virtual_addr = NULL;
+		core->iface_queues[i].q_array.align_device_addr = 0;
+	}
+
+	core->iface_q_table.align_virtual_addr = NULL;
+	core->iface_q_table.align_device_addr = 0;
+
+	core->sfr.align_virtual_addr = NULL;
+	core->sfr.align_device_addr = 0;
+}
+
+int venus_hfi_reset_queue_header(struct msm_vidc_core *core)
+{
+	struct msm_vidc_iface_q_info *iface_q;
+	struct hfi_queue_header *q_hdr;
+	int i;
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		iface_q = &core->iface_queues[i];
+		__set_queue_hdr_defaults(iface_q->q_hdr);
+	}
+
+	iface_q = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+
+	iface_q = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+
+	iface_q = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = 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;
+
+	return 0;
+}
+
+int venus_hfi_queue_init(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct hfi_queue_table_header *q_tbl_hdr;
+	struct hfi_queue_header *q_hdr;
+	struct msm_vidc_iface_q_info *iface_q;
+	struct msm_vidc_mem mem;
+	int offset = 0;
+	u32 i;
+
+	if (core->iface_q_table.align_virtual_addr) {
+		d_vpr_h("%s: queues already allocated\n", __func__);
+		venus_hfi_reset_queue_header(core);
+		return 0;
+	}
+
+	memset(&mem, 0, sizeof(mem));
+	mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE;
+	mem.region = MSM_VIDC_NON_SECURE;
+	mem.size = TOTAL_QSIZE;
+	mem.secure = false;
+	mem.map_kernel = true;
+	rc = call_mem_op(core, memory_alloc_map, core, &mem);
+	if (rc) {
+		d_vpr_e("%s: alloc and map failed\n", __func__);
+		goto fail_alloc_queue;
+	}
+	core->iface_q_table.align_virtual_addr = mem.kvaddr;
+	core->iface_q_table.align_device_addr = mem.device_addr;
+	core->iface_q_table.mem = mem;
+
+	core->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
+	offset += core->iface_q_table.mem_size;
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		iface_q = &core->iface_queues[i];
+		iface_q->q_array.align_device_addr = mem.device_addr + offset;
+		iface_q->q_array.align_virtual_addr = (void *)((char *)mem.kvaddr + offset);
+		iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
+		offset += iface_q->q_array.mem_size;
+		iface_q->q_hdr =
+			VIDC_IFACEQ_GET_QHDR_START_ADDR(core->iface_q_table.align_virtual_addr, i);
+		__set_queue_hdr_defaults(iface_q->q_hdr);
+	}
+
+	q_tbl_hdr = (struct hfi_queue_table_header *)
+			core->iface_q_table.align_virtual_addr;
+	q_tbl_hdr->qtbl_version = 0;
+	q_tbl_hdr->device_addr = (void *)core;
+	strscpy(q_tbl_hdr->name, "msm_v4l2_vidc", sizeof(q_tbl_hdr->name));
+	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 = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+
+	iface_q = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+
+	iface_q = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = 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;
+
+	/* sfr buffer */
+	memset(&mem, 0, sizeof(mem));
+	mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE;
+	mem.region = MSM_VIDC_NON_SECURE;
+	mem.size = ALIGNED_SFR_SIZE;
+	mem.secure = false;
+	mem.map_kernel = true;
+	rc = call_mem_op(core, memory_alloc_map, core, &mem);
+	if (rc) {
+		d_vpr_e("%s: sfr alloc and map failed\n", __func__);
+		goto fail_alloc_queue;
+	}
+	core->sfr.align_virtual_addr = mem.kvaddr;
+	core->sfr.align_device_addr = mem.device_addr;
+	core->sfr.mem = mem;
+
+	core->sfr.mem_size = ALIGNED_SFR_SIZE;
+	/* write sfr buffer size in first word */
+	*((u32 *)core->sfr.align_virtual_addr) = core->sfr.mem_size;
+
+	return 0;
+
+fail_alloc_queue:
+	return -ENOMEM;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 21/33] iris: vidc: hfi: Add packetization layer
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (19 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 22/33] iris: vidc: hfi: defines HFI properties and enums Vikash Garodia
                   ` (14 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

This implements hfi packets used to communicate the info
to/from firmware.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/hfi_command.h      | 190 ++++++
 .../media/platform/qcom/iris/vidc/inc/hfi_packet.h |  52 ++
 .../media/platform/qcom/iris/vidc/src/hfi_packet.c | 657 +++++++++++++++++++++
 3 files changed, 899 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h b/drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
new file mode 100644
index 0000000..5542e56
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __H_HFI_COMMAND_H__
+#define __H_HFI_COMMAND_H__
+
+//todo: DP: remove below headers
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define HFI_VIDEO_ARCH_LX               0x1
+
+struct hfi_header {
+	u32 size;
+	u32 session_id;
+	u32 header_id;
+	u32 reserved[4];
+	u32 num_packets;
+};
+
+struct hfi_packet {
+	u32 size;
+	u32 type;
+	u32 flags;
+	u32 payload_info;
+	u32 port;
+	u32 packet_id;
+	u32 reserved[2];
+};
+
+struct hfi_buffer {
+	u32 type;
+	u32 index;
+	u64 base_address;
+	u32 addr_offset;
+	u32 buffer_size;
+	u32 data_offset;
+	u32 data_size;
+	u64 timestamp;
+	u32 flags;
+	u32 reserved[5];
+};
+
+enum hfi_packet_host_flags {
+	HFI_HOST_FLAGS_NONE                = 0x00000000,
+	HFI_HOST_FLAGS_INTR_REQUIRED       = 0x00000001,
+	HFI_HOST_FLAGS_RESPONSE_REQUIRED   = 0x00000002,
+	HFI_HOST_FLAGS_NON_DISCARDABLE     = 0x00000004,
+	HFI_HOST_FLAGS_GET_PROPERTY        = 0x00000008,
+};
+
+enum hfi_packet_firmware_flags {
+	HFI_FW_FLAGS_NONE          = 0x00000000,
+	HFI_FW_FLAGS_SUCCESS       = 0x00000001,
+	HFI_FW_FLAGS_INFORMATION   = 0x00000002,
+	HFI_FW_FLAGS_SESSION_ERROR = 0x00000004,
+	HFI_FW_FLAGS_SYSTEM_ERROR  = 0x00000008,
+};
+
+enum hfi_packet_payload_info {
+	HFI_PAYLOAD_NONE      = 0x00000000,
+	HFI_PAYLOAD_U32       = 0x00000001,
+	HFI_PAYLOAD_S32       = 0x00000002,
+	HFI_PAYLOAD_U64       = 0x00000003,
+	HFI_PAYLOAD_S64       = 0x00000004,
+	HFI_PAYLOAD_STRUCTURE = 0x00000005,
+	HFI_PAYLOAD_BLOB      = 0x00000006,
+	HFI_PAYLOAD_STRING    = 0x00000007,
+	HFI_PAYLOAD_Q16       = 0x00000008,
+	HFI_PAYLOAD_U32_ENUM  = 0x00000009,
+	HFI_PAYLOAD_32_PACKED = 0x0000000a,
+	HFI_PAYLOAD_U32_ARRAY = 0x0000000b,
+	HFI_PAYLOAD_S32_ARRAY = 0x0000000c,
+	HFI_PAYLOAD_64_PACKED = 0x0000000d,
+};
+
+enum hfi_packet_port_type {
+	HFI_PORT_NONE      = 0x00000000,
+	HFI_PORT_BITSTREAM = 0x00000001,
+	HFI_PORT_RAW       = 0x00000002,
+};
+
+enum hfi_buffer_type {
+	HFI_BUFFER_BITSTREAM      = 0x00000001,
+	HFI_BUFFER_RAW            = 0x00000002,
+	HFI_BUFFER_METADATA       = 0x00000003,
+	HFI_BUFFER_SUBCACHE       = 0x00000004,
+	HFI_BUFFER_PARTIAL_DATA   = 0x00000005,
+	HFI_BUFFER_DPB            = 0x00000006,
+	HFI_BUFFER_BIN            = 0x00000007,
+	HFI_BUFFER_LINE           = 0x00000008,
+	HFI_BUFFER_ARP            = 0x00000009,
+	HFI_BUFFER_COMV           = 0x0000000A,
+	HFI_BUFFER_NON_COMV       = 0x0000000B,
+	HFI_BUFFER_PERSIST        = 0x0000000C,
+	HFI_BUFFER_VPSS           = 0x0000000D,
+};
+
+enum hfi_buffer_host_flags {
+	HFI_BUF_HOST_FLAG_NONE               = 0x00000000,
+	HFI_BUF_HOST_FLAG_RELEASE            = 0x00000001,
+	HFI_BUF_HOST_FLAG_READONLY           = 0x00000010,
+	HFI_BUF_HOST_FLAG_CODEC_CONFIG       = 0x00000100,
+	HFI_BUF_HOST_FLAGS_CB_NON_SECURE       = 0x00000200,
+	HFI_BUF_HOST_FLAGS_CB_SECURE_PIXEL     = 0x00000400,
+	HFI_BUF_HOST_FLAGS_CB_SECURE_BITSTREAM = 0x00000800,
+	HFI_BUF_HOST_FLAGS_CB_SECURE_NON_PIXEL = 0x00001000,
+	HFI_BUF_HOST_FLAGS_CB_NON_SECURE_PIXEL = 0x00002000,
+};
+
+enum hfi_buffer_firmware_flags {
+	HFI_BUF_FW_FLAG_NONE            = 0x00000000,
+	HFI_BUF_FW_FLAG_RELEASE_DONE    = 0x00000001,
+	HFI_BUF_FW_FLAG_READONLY        = 0x00000010,
+	HFI_BUF_FW_FLAG_CODEC_CONFIG    = 0x00000100,
+	HFI_BUF_FW_FLAG_LAST            = 0x10000000,
+	HFI_BUF_FW_FLAG_PSC_LAST        = 0x20000000,
+};
+
+enum hfi_metapayload_header_flags {
+	HFI_METADATA_FLAGS_NONE         = 0x00000000,
+	HFI_METADATA_FLAGS_TOP_FIELD    = 0x00000001,
+	HFI_METADATA_FLAGS_BOTTOM_FIELD = 0x00000002,
+};
+
+struct metabuf_header {
+	u32 count;
+	u32 size;
+	u32 version;
+	u32 reserved[5];
+};
+
+struct metapayload_header {
+	u32 type;
+	u32 size;
+	u32 version;
+	u32 offset;
+	u32 flags;
+	u32 reserved[3];
+};
+
+enum hfi_property_mode_type {
+	HFI_MODE_NONE                 = 0x00000000,
+	HFI_MODE_PORT_SETTINGS_CHANGE = 0x00000001,
+	HFI_MODE_PROPERTY             = 0x00000002,
+	HFI_MODE_METADATA             = 0x00000004,
+	HFI_MODE_DYNAMIC_METADATA     = 0x00000005,
+};
+
+enum hfi_reserve_type {
+	HFI_RESERVE_START = 0x1,
+	HFI_RESERVE_STOP  = 0x2,
+};
+
+#define HFI_CMD_BEGIN                                           0x01000000
+#define HFI_CMD_INIT                                            0x01000001
+#define HFI_CMD_POWER_COLLAPSE                                  0x01000002
+#define HFI_CMD_OPEN                                            0x01000003
+#define HFI_CMD_CLOSE                                           0x01000004
+#define HFI_CMD_START                                           0x01000005
+#define HFI_CMD_STOP                                            0x01000006
+#define HFI_CMD_DRAIN                                           0x01000007
+#define HFI_CMD_RESUME                                          0x01000008
+#define HFI_CMD_BUFFER                                          0x01000009
+#define HFI_CMD_DELIVERY_MODE                                   0x0100000A
+#define HFI_CMD_SUBSCRIBE_MODE                                  0x0100000B
+#define HFI_CMD_SETTINGS_CHANGE                                 0x0100000C
+
+#define HFI_SSR_TYPE_SW_ERR_FATAL       0x1
+#define HFI_SSR_TYPE_SW_DIV_BY_ZERO     0x2
+#define HFI_SSR_TYPE_CPU_WDOG_IRQ       0x3
+#define HFI_SSR_TYPE_NOC_ERROR          0x4
+#define HFI_BITMASK_HW_CLIENT_ID                        0x000000f0
+#define HFI_BITMASK_SSR_TYPE                            0x0000000f
+#define HFI_CMD_SSR                                             0x0100000D
+
+#define HFI_STABILITY_TYPE_VCODEC_HUNG        0x1
+#define HFI_STABILITY_TYPE_ENC_BUFFER_FULL    0x2
+#define HFI_BITMASK_STABILITY_TYPE                      0x0000000f
+#define HFI_CMD_STABILITY                                       0x0100000E
+
+#define HFI_CMD_RESERVE                                         0x0100000F
+#define HFI_CMD_FLUSH                                           0x01000010
+#define HFI_CMD_PAUSE                                           0x01000011
+#define HFI_CMD_END                                             0x01FFFFFF
+
+#endif //__H_HFI_COMMAND_H__
diff --git a/drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h b/drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
new file mode 100644
index 0000000..dc19c85
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _HFI_PACKET_H_
+#define _HFI_PACKET_H_
+
+#include "hfi_command.h"
+#include "hfi_property.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+u32 get_hfi_port(struct msm_vidc_inst *inst,
+		 enum msm_vidc_port_type port);
+u32 get_hfi_port_from_buffer_type(struct msm_vidc_inst *inst,
+				  enum msm_vidc_buffer_type buffer_type);
+u32 hfi_buf_type_from_driver(enum msm_vidc_domain_type domain,
+			     enum msm_vidc_buffer_type buffer_type);
+u32 hfi_buf_type_to_driver(enum msm_vidc_domain_type domain,
+			   enum hfi_buffer_type buffer_type,
+			   enum hfi_packet_port_type port_type);
+u32 get_hfi_codec(struct msm_vidc_inst *inst);
+u32 get_hfi_colorformat(struct msm_vidc_inst *inst,
+			enum msm_vidc_colorformat_type colorformat);
+int get_hfi_buffer(struct msm_vidc_inst *inst,
+		   struct msm_vidc_buffer *buffer, struct hfi_buffer *buf);
+int hfi_create_header(u8 *packet, u32 packet_size,
+		      u32 session_id, u32 header_id);
+int hfi_create_packet(u8 *packet, u32 packet_size,
+		      u32 pkt_type, u32 pkt_flags, u32 payload_type, u32 port,
+		      u32 packet_id, void *payload, u32 payload_size);
+int hfi_create_buffer(u8 *packet, u32 packet_size, u32 *offset,
+		      enum msm_vidc_domain_type domain,
+		      struct msm_vidc_buffer *data);
+int hfi_packet_sys_init(struct msm_vidc_core *core,
+			u8 *pkt, u32 pkt_size);
+int hfi_packet_image_version(struct msm_vidc_core *core,
+			     u8 *pkt, u32 pkt_size);
+int hfi_packet_sys_pc_prep(struct msm_vidc_core *core,
+			   u8 *pkt, u32 pkt_size);
+int hfi_packet_sys_debug_config(struct msm_vidc_core *core, u8 *pkt,
+				u32 pkt_size, u32 debug_config);
+int hfi_packet_session_command(struct msm_vidc_inst *inst, u32 pkt_type,
+			       u32 flags, u32 port, u32 session_id,
+			       u32 payload_type, void *payload, u32 payload_size);
+int hfi_packet_sys_intraframe_powercollapse(struct msm_vidc_core *core, u8 *pkt,
+					    u32 pkt_size, u32 enable);
+
+#endif // _HFI_PACKET_H_
diff --git a/drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c b/drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
new file mode 100644
index 0000000..2cf777c
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
@@ -0,0 +1,657 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_packet.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_platform.h"
+
+u32 get_hfi_port(struct msm_vidc_inst *inst,
+		 enum msm_vidc_port_type port)
+{
+	u32 hfi_port = HFI_PORT_NONE;
+
+	if (is_decode_session(inst)) {
+		switch (port) {
+		case INPUT_PORT:
+			hfi_port = HFI_PORT_BITSTREAM;
+			break;
+		case OUTPUT_PORT:
+			hfi_port = HFI_PORT_RAW;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid port type %d\n",
+				__func__, port);
+			break;
+		}
+	} else if (is_encode_session(inst)) {
+		switch (port) {
+		case INPUT_PORT:
+			hfi_port = HFI_PORT_RAW;
+			break;
+		case OUTPUT_PORT:
+			hfi_port = HFI_PORT_BITSTREAM;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid port type %d\n",
+				__func__, port);
+			break;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %#x\n",
+			__func__, inst->domain);
+	}
+
+	return hfi_port;
+}
+
+u32 get_hfi_port_from_buffer_type(struct msm_vidc_inst *inst,
+				  enum msm_vidc_buffer_type buffer_type)
+{
+	u32 hfi_port = HFI_PORT_NONE;
+
+	if (is_decode_session(inst)) {
+		switch (buffer_type) {
+		case MSM_VIDC_BUF_INPUT:
+		case MSM_VIDC_BUF_BIN:
+		case MSM_VIDC_BUF_COMV:
+		case MSM_VIDC_BUF_NON_COMV:
+		case MSM_VIDC_BUF_LINE:
+			hfi_port = HFI_PORT_BITSTREAM;
+			break;
+		case MSM_VIDC_BUF_OUTPUT:
+		case MSM_VIDC_BUF_DPB:
+			hfi_port = HFI_PORT_RAW;
+			break;
+		case MSM_VIDC_BUF_PERSIST:
+			hfi_port = HFI_PORT_NONE;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid buffer type %d\n",
+				__func__, buffer_type);
+			break;
+		}
+	} else if (is_encode_session(inst)) {
+		switch (buffer_type) {
+		case MSM_VIDC_BUF_INPUT:
+		case MSM_VIDC_BUF_VPSS:
+			hfi_port = HFI_PORT_RAW;
+			break;
+		case MSM_VIDC_BUF_OUTPUT:
+		case MSM_VIDC_BUF_BIN:
+		case MSM_VIDC_BUF_COMV:
+		case MSM_VIDC_BUF_NON_COMV:
+		case MSM_VIDC_BUF_LINE:
+		case MSM_VIDC_BUF_DPB:
+			hfi_port = HFI_PORT_BITSTREAM;
+			break;
+		case MSM_VIDC_BUF_ARP:
+			hfi_port = HFI_PORT_NONE;
+			break;
+		default:
+			i_vpr_e(inst, "%s: invalid buffer type %d\n",
+				__func__, buffer_type);
+			break;
+		}
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %#x\n",
+			__func__, inst->domain);
+	}
+
+	return hfi_port;
+}
+
+u32 hfi_buf_type_from_driver(enum msm_vidc_domain_type domain,
+			     enum msm_vidc_buffer_type buffer_type)
+{
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_INPUT:
+		if (domain == MSM_VIDC_DECODER)
+			return HFI_BUFFER_BITSTREAM;
+		else
+			return HFI_BUFFER_RAW;
+	case MSM_VIDC_BUF_OUTPUT:
+		if (domain == MSM_VIDC_DECODER)
+			return HFI_BUFFER_RAW;
+		else
+			return HFI_BUFFER_BITSTREAM;
+	case MSM_VIDC_BUF_BIN:
+		return HFI_BUFFER_BIN;
+	case MSM_VIDC_BUF_ARP:
+		return HFI_BUFFER_ARP;
+	case MSM_VIDC_BUF_COMV:
+		return HFI_BUFFER_COMV;
+	case MSM_VIDC_BUF_NON_COMV:
+		return HFI_BUFFER_NON_COMV;
+	case MSM_VIDC_BUF_LINE:
+		return HFI_BUFFER_LINE;
+	case MSM_VIDC_BUF_DPB:
+		return HFI_BUFFER_DPB;
+	case MSM_VIDC_BUF_PERSIST:
+		return HFI_BUFFER_PERSIST;
+	case MSM_VIDC_BUF_VPSS:
+		return HFI_BUFFER_VPSS;
+	default:
+		d_vpr_e("invalid buffer type %d\n",
+			buffer_type);
+		return 0;
+	}
+}
+
+u32 hfi_buf_type_to_driver(enum msm_vidc_domain_type domain,
+			   enum hfi_buffer_type buffer_type,
+			   enum hfi_packet_port_type port_type)
+{
+	switch (buffer_type) {
+	case HFI_BUFFER_BITSTREAM:
+		if (domain == MSM_VIDC_DECODER)
+			return MSM_VIDC_BUF_INPUT;
+		else
+			return MSM_VIDC_BUF_OUTPUT;
+	case HFI_BUFFER_RAW:
+		if (domain == MSM_VIDC_DECODER)
+			return MSM_VIDC_BUF_OUTPUT;
+		else
+			return MSM_VIDC_BUF_INPUT;
+	case HFI_BUFFER_BIN:
+		return MSM_VIDC_BUF_BIN;
+	case HFI_BUFFER_ARP:
+		return MSM_VIDC_BUF_ARP;
+	case HFI_BUFFER_COMV:
+		return MSM_VIDC_BUF_COMV;
+	case HFI_BUFFER_NON_COMV:
+		return MSM_VIDC_BUF_NON_COMV;
+	case HFI_BUFFER_LINE:
+		return MSM_VIDC_BUF_LINE;
+	case HFI_BUFFER_DPB:
+		return MSM_VIDC_BUF_DPB;
+	case HFI_BUFFER_PERSIST:
+		return MSM_VIDC_BUF_PERSIST;
+	case HFI_BUFFER_VPSS:
+		return MSM_VIDC_BUF_VPSS;
+	default:
+		d_vpr_e("invalid buffer type %d\n",
+			buffer_type);
+		return 0;
+	}
+}
+
+u32 get_hfi_codec(struct msm_vidc_inst *inst)
+{
+	switch (inst->codec) {
+	case MSM_VIDC_H264:
+		if (is_encode_session(inst))
+			return HFI_CODEC_ENCODE_AVC;
+		else
+			return HFI_CODEC_DECODE_AVC;
+	case MSM_VIDC_HEVC:
+		if (is_encode_session(inst))
+			return HFI_CODEC_ENCODE_HEVC;
+		else
+			return HFI_CODEC_DECODE_HEVC;
+	case MSM_VIDC_VP9:
+		return HFI_CODEC_DECODE_VP9;
+	default:
+		i_vpr_e(inst, "invalid codec %d, domain %d\n",
+			inst->codec, inst->domain);
+		return 0;
+	}
+}
+
+u32 get_hfi_colorformat(struct msm_vidc_inst *inst,
+			enum msm_vidc_colorformat_type colorformat)
+{
+	u32 hfi_colorformat = HFI_COLOR_FMT_NV12_UBWC;
+
+	switch (colorformat) {
+	case MSM_VIDC_FMT_NV12:
+		hfi_colorformat = HFI_COLOR_FMT_NV12;
+		break;
+	case MSM_VIDC_FMT_NV12C:
+		hfi_colorformat = HFI_COLOR_FMT_NV12_UBWC;
+		break;
+	case MSM_VIDC_FMT_P010:
+		hfi_colorformat = HFI_COLOR_FMT_P010;
+		break;
+	case MSM_VIDC_FMT_TP10C:
+		hfi_colorformat = HFI_COLOR_FMT_TP10_UBWC;
+		break;
+	case MSM_VIDC_FMT_RGBA8888:
+		hfi_colorformat = HFI_COLOR_FMT_RGBA8888;
+		break;
+	case MSM_VIDC_FMT_RGBA8888C:
+		hfi_colorformat = HFI_COLOR_FMT_RGBA8888_UBWC;
+		break;
+	case MSM_VIDC_FMT_NV21:
+		hfi_colorformat = HFI_COLOR_FMT_NV21;
+		break;
+	default:
+		i_vpr_e(inst, "%s: invalid colorformat %d\n",
+			__func__, colorformat);
+		break;
+	}
+
+	return hfi_colorformat;
+}
+
+static u32 get_hfi_region_flag(enum msm_vidc_buffer_region region)
+{
+	switch (region) {
+	case MSM_VIDC_NON_SECURE:
+		return HFI_BUF_HOST_FLAGS_CB_NON_SECURE;
+	case MSM_VIDC_NON_SECURE_PIXEL:
+		return HFI_BUF_HOST_FLAGS_CB_NON_SECURE_PIXEL;
+	case MSM_VIDC_SECURE_PIXEL:
+		return HFI_BUF_HOST_FLAGS_CB_SECURE_PIXEL;
+	case MSM_VIDC_SECURE_NONPIXEL:
+		return HFI_BUF_HOST_FLAGS_CB_SECURE_NON_PIXEL;
+	case MSM_VIDC_SECURE_BITSTREAM:
+		return HFI_BUF_HOST_FLAGS_CB_SECURE_BITSTREAM;
+	case MSM_VIDC_REGION_MAX:
+	case MSM_VIDC_REGION_NONE:
+	default:
+		return HFI_BUF_HOST_FLAG_NONE;
+	}
+}
+
+int get_hfi_buffer(struct msm_vidc_inst *inst,
+		   struct msm_vidc_buffer *buffer, struct hfi_buffer *buf)
+{
+	memset(buf, 0, sizeof(struct hfi_buffer));
+	buf->type = hfi_buf_type_from_driver(inst->domain, buffer->type);
+	buf->index = buffer->index;
+	buf->base_address = buffer->device_addr;
+	buf->addr_offset = 0;
+	buf->buffer_size = buffer->buffer_size;
+	/*
+	 * for decoder input buffers, firmware (BSE HW) needs 256 aligned
+	 * buffer size otherwise it will truncate or ignore the data after 256
+	 * aligned size which may lead to error concealment
+	 */
+	if (is_decode_session(inst) && is_input_buffer(buffer->type))
+		buf->buffer_size = ALIGN(buffer->buffer_size, 256);
+	buf->data_offset = buffer->data_offset;
+	buf->data_size = buffer->data_size;
+	if (buffer->attr & MSM_VIDC_ATTR_READ_ONLY)
+		buf->flags |= HFI_BUF_HOST_FLAG_READONLY;
+	if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE)
+		buf->flags |= HFI_BUF_HOST_FLAG_RELEASE;
+	buf->flags |= get_hfi_region_flag(buffer->region);
+	buf->timestamp = buffer->timestamp;
+
+	return 0;
+}
+
+int hfi_create_header(u8 *packet, u32 packet_size, u32 session_id,
+		      u32 header_id)
+{
+	struct hfi_header *hdr = (struct hfi_header *)packet;
+
+	if (!packet || packet_size < sizeof(struct hfi_header)) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(hdr, 0, sizeof(struct hfi_header));
+
+	hdr->size = sizeof(struct hfi_header);
+	hdr->session_id = session_id;
+	hdr->header_id = header_id;
+	hdr->num_packets = 0;
+	return 0;
+}
+
+int hfi_create_packet(u8 *packet, u32 packet_size, u32 pkt_type,
+		      u32 pkt_flags, u32 payload_type, u32 port,
+		      u32 packet_id, void *payload, u32 payload_size)
+{
+	struct hfi_header *hdr;
+	struct hfi_packet *pkt;
+	u32 pkt_size;
+
+	if (!packet) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdr = (struct hfi_header *)packet;
+	if (hdr->size < sizeof(struct hfi_header)) {
+		d_vpr_e("%s: invalid hdr size %d\n", __func__, hdr->size);
+		return -EINVAL;
+	}
+	pkt = (struct hfi_packet *)(packet + hdr->size);
+	pkt_size = sizeof(struct hfi_packet) + payload_size;
+	if (packet_size < hdr->size  + pkt_size) {
+		d_vpr_e("%s: invalid packet_size %d, %d %d\n",
+			__func__, packet_size, hdr->size, pkt_size);
+		return -EINVAL;
+	}
+	memset(pkt, 0, pkt_size);
+	pkt->size = pkt_size;
+	pkt->type = pkt_type;
+	pkt->flags = pkt_flags;
+	pkt->payload_info = payload_type;
+	pkt->port = port;
+	pkt->packet_id = packet_id;
+	if (payload_size)
+		memcpy((u8 *)pkt + sizeof(struct hfi_packet),
+		       payload, payload_size);
+
+	hdr->num_packets++;
+	hdr->size += pkt->size;
+	return 0;
+}
+
+int hfi_packet_sys_init(struct msm_vidc_core *core,
+			u8 *pkt, u32 pkt_size)
+{
+	int rc = 0;
+	u32 payload = 0;
+
+	rc = hfi_create_header(pkt, pkt_size,
+			       0 /*session_id*/,
+			       core->header_id++);
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_CMD_SYSTEM_INIT */
+	payload = HFI_VIDEO_ARCH_LX;
+	d_vpr_h("%s: arch %d\n", __func__, payload);
+	core->sys_init_id = core->packet_id++;
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_CMD_INIT,
+			       (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+			       HFI_HOST_FLAGS_INTR_REQUIRED |
+			       HFI_HOST_FLAGS_NON_DISCARDABLE),
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->sys_init_id,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_MAX_CHANNELS */
+	payload = core->platform->data.ubwc_config->max_channels;
+	d_vpr_h("%s: ubwc max channels %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_MAX_CHANNELS,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_MAL_LENGTH */
+	payload = core->platform->data.ubwc_config->mal_length;
+	d_vpr_h("%s: ubwc mal length %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_MAL_LENGTH,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_HBB */
+	payload = core->platform->data.ubwc_config->highest_bank_bit;
+	d_vpr_h("%s: ubwc hbb %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_HBB,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_BANK_SWZL_LEVEL1 */
+	payload = core->platform->data.ubwc_config->bank_swzl_level;
+	d_vpr_h("%s: ubwc swzl1 %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_BANK_SWZL_LEVEL1,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_BANK_SWZL_LEVEL2 */
+	payload = core->platform->data.ubwc_config->bank_swz2_level;
+	d_vpr_h("%s: ubwc swzl2 %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_BANK_SWZL_LEVEL2,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_BANK_SWZL_LEVEL3 */
+	payload = core->platform->data.ubwc_config->bank_swz3_level;
+	d_vpr_h("%s: ubwc swzl3 %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_BANK_SWZL_LEVEL3,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	/* HFI_PROP_UBWC_BANK_SPREADING */
+	payload = core->platform->data.ubwc_config->bank_spreading;
+	d_vpr_h("%s: ubwc bank spreading %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_UBWC_BANK_SPREADING,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_sys_init;
+
+	d_vpr_h("System init packet created\n");
+	return rc;
+
+err_sys_init:
+	d_vpr_e("%s: create packet failed\n", __func__);
+	return rc;
+}
+
+int hfi_packet_image_version(struct msm_vidc_core *core,
+			     u8 *pkt, u32 pkt_size)
+{
+	int rc = 0;
+
+	rc = hfi_create_header(pkt, pkt_size,
+			       0 /*session_id*/,
+			       core->header_id++);
+	if (rc)
+		goto err_img_version;
+
+	/* HFI_PROP_IMAGE_VERSION */
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_IMAGE_VERSION,
+			       (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+			       HFI_HOST_FLAGS_INTR_REQUIRED |
+			       HFI_HOST_FLAGS_GET_PROPERTY),
+			       HFI_PAYLOAD_NONE,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       NULL, 0);
+	if (rc)
+		goto err_img_version;
+
+	d_vpr_h("Image version packet created\n");
+	return rc;
+
+err_img_version:
+	d_vpr_e("%s: create packet failed\n", __func__);
+	return rc;
+}
+
+int hfi_packet_sys_pc_prep(struct msm_vidc_core *core,
+			   u8 *pkt, u32 pkt_size)
+{
+	int rc = 0;
+
+	rc = hfi_create_header(pkt, pkt_size,
+			       0 /*session_id*/,
+			       core->header_id++);
+	if (rc)
+		goto err_sys_pc;
+
+	/* HFI_CMD_POWER_COLLAPSE */
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_CMD_POWER_COLLAPSE,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_NONE,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       NULL, 0);
+	if (rc)
+		goto err_sys_pc;
+
+	d_vpr_h("Power collapse packet created\n");
+	return rc;
+
+err_sys_pc:
+	d_vpr_e("%s: create packet failed\n", __func__);
+	return rc;
+}
+
+int hfi_packet_sys_debug_config(struct msm_vidc_core *core,
+				u8 *pkt, u32 pkt_size, u32 debug_config)
+{
+	int rc = 0;
+	u32 payload = 0;
+
+	rc = hfi_create_header(pkt, pkt_size,
+			       0 /*session_id*/,
+			       core->header_id++);
+	if (rc)
+		goto err_debug;
+
+	/* HFI_PROP_DEBUG_CONFIG */
+	payload = 0; /*TODO:Change later*/
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_DEBUG_CONFIG,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32_ENUM,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_debug;
+
+	/* HFI_PROP_DEBUG_LOG_LEVEL */
+	payload = debug_config; /*TODO:Change later*/
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_DEBUG_LOG_LEVEL,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32_ENUM,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err_debug;
+
+err_debug:
+	if (rc)
+		d_vpr_e("%s: create packet failed\n", __func__);
+
+	return rc;
+}
+
+int hfi_packet_session_command(struct msm_vidc_inst *inst, u32 pkt_type,
+			       u32 flags, u32 port, u32 session_id,
+			       u32 payload_type, void *payload, u32 payload_size)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	rc = hfi_create_header(inst->packet, inst->packet_size,
+			       session_id, core->header_id++);
+	if (rc)
+		goto err_cmd;
+
+	rc = hfi_create_packet(inst->packet,
+			       inst->packet_size,
+			       pkt_type,
+			       flags,
+			       payload_type,
+			       port,
+			       core->packet_id++,
+			       payload,
+			       payload_size);
+	if (rc)
+		goto err_cmd;
+
+	i_vpr_h(inst, "Command packet 0x%x created\n", pkt_type);
+	return rc;
+
+err_cmd:
+	i_vpr_e(inst, "%s: create packet failed\n", __func__);
+	return rc;
+}
+
+int hfi_packet_sys_intraframe_powercollapse(struct msm_vidc_core *core,
+					    u8 *pkt, u32 pkt_size, u32 enable)
+{
+	int rc = 0;
+	u32 payload = 0;
+
+	rc = hfi_create_header(pkt, pkt_size,
+			       0 /*session_id*/,
+			       core->header_id++);
+	if (rc)
+		goto err;
+
+	/* HFI_PROP_INTRA_FRAME_POWER_COLLAPSE */
+	payload = enable;
+	d_vpr_h("%s: intra frame power collapse %d\n", __func__, payload);
+	rc = hfi_create_packet(pkt, pkt_size,
+			       HFI_PROP_INTRA_FRAME_POWER_COLLAPSE,
+			       HFI_HOST_FLAGS_NONE,
+			       HFI_PAYLOAD_U32,
+			       HFI_PORT_NONE,
+			       core->packet_id++,
+			       &payload,
+			       sizeof(u32));
+	if (rc)
+		goto err;
+
+	d_vpr_h("IFPC packet created\n");
+	return rc;
+
+err:
+	d_vpr_e("%s: create packet failed\n", __func__);
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 22/33] iris: vidc: hfi: defines HFI properties and enums
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (20 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 21/33] iris: vidc: hfi: Add packetization layer Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 23/33] iris: vidc: add PIL functionality for video firmware Vikash Garodia
                   ` (13 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

Defines hfi properties supported by firmware and enums like
codec, colorformat, profile, level, rate control etc.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/hfi_property.h     | 666 +++++++++++++++++++++
 1 file changed, 666 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h b/drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
new file mode 100644
index 0000000..3fb6601
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
@@ -0,0 +1,666 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __H_HFI_PROPERTY_H__
+#define __H_HFI_PROPERTY_H__
+
+//todo: DP: remove below header
+#include <linux/types.h>
+
+#define HFI_PROP_BEGIN                                          0x03000000
+#define HFI_PROP_IMAGE_VERSION                                  0x03000001
+#define HFI_PROP_INTRA_FRAME_POWER_COLLAPSE                     0x03000002
+#define HFI_PROP_UBWC_MAX_CHANNELS                              0x03000003
+#define HFI_PROP_UBWC_MAL_LENGTH                                0x03000004
+#define HFI_PROP_UBWC_HBB                                       0x03000005
+#define HFI_PROP_UBWC_BANK_SWZL_LEVEL1                          0x03000006
+#define HFI_PROP_UBWC_BANK_SWZL_LEVEL2                          0x03000007
+#define HFI_PROP_UBWC_BANK_SWZL_LEVEL3                          0x03000008
+#define HFI_PROP_UBWC_BANK_SPREADING                            0x03000009
+
+enum hfi_debug_config {
+	HFI_DEBUG_CONFIG_DEFAULT = 0x00000000,
+	HFI_DEBUG_CONFIG_CLRDBGQ = 0x00000001,
+	HFI_DEBUG_CONFIG_WFI     = 0x00000002,
+	HFI_DEBUG_CONFIG_ARM9WD  = 0x00000004,
+};
+
+#define HFI_PROP_DEBUG_CONFIG                                   0x0300000a
+
+enum hfi_debug_log_level {
+	HFI_DEBUG_LOG_NONE   = 0x00000000,
+	HFI_DEBUG_LOG_ERROR  = 0x00000001,
+	HFI_DEBUG_LOG_FATAL  = 0x00000002,
+	HFI_DEBUG_LOG_PERF   = 0x00000004,
+	HFI_DEBUG_LOG_HIGH   = 0x00000008,
+	HFI_DEBUG_LOG_MEDIUM = 0x00000010,
+	HFI_DEBUG_LOG_LOW    = 0x00000020,
+};
+
+struct hfi_debug_header {
+	u32   size;
+	u32   debug_level;
+	u32   reserved[2];
+};
+
+#define HFI_PROP_DEBUG_LOG_LEVEL                                0x0300000b
+
+#define HFI_PROP_FENCE_CLIENT_DATA                              0x0300000d
+
+enum hfi_codec_type {
+	HFI_CODEC_DECODE_AVC   = 1,
+	HFI_CODEC_ENCODE_AVC   = 2,
+	HFI_CODEC_DECODE_HEVC  = 3,
+	HFI_CODEC_ENCODE_HEVC  = 4,
+	HFI_CODEC_DECODE_VP9   = 5,
+	HFI_CODEC_DECODE_MPEG2 = 6,
+	HFI_CODEC_DECODE_AV1   = 7,
+};
+
+#define HFI_PROP_CODEC                                          0x03000100
+
+enum hfi_color_format {
+	HFI_COLOR_FMT_OPAQUE        = 0,
+	HFI_COLOR_FMT_NV12          = 1,
+	HFI_COLOR_FMT_NV12_UBWC     = 2,
+	HFI_COLOR_FMT_P010          = 3,
+	HFI_COLOR_FMT_TP10_UBWC     = 4,
+	HFI_COLOR_FMT_RGBA8888      = 5,
+	HFI_COLOR_FMT_RGBA8888_UBWC = 6,
+	HFI_COLOR_FMT_NV21          = 7,
+};
+
+#define HFI_PROP_COLOR_FORMAT                                   0x03000101
+
+#define HFI_PROP_SECURE                                         0x03000102
+
+#define HFI_BITMASK_BITSTREAM_WIDTH                             0xffff0000
+#define HFI_BITMASK_BITSTREAM_HEIGHT                            0x0000ffff
+#define HFI_PROP_BITSTREAM_RESOLUTION                           0x03000103
+
+#define HFI_BITMASK_LINEAR_STRIDE             0xffff0000
+#define HFI_BITMASK_LINEAR_SCANLINE           0x0000ffff
+#define HFI_PROP_LINEAR_STRIDE_SCANLINE                        0x03000104
+
+#define HFI_BITMASK_CROP_RIGHT_OFFSET        0xffff0000
+#define HFI_BITMASK_CROP_BOTTOM_OFFSET       0x0000ffff
+#define HFI_BITMASK_CROP_LEFT_OFFSET         0xffff0000
+#define HFI_BITMASK_CROP_TOP_OFFSET          0x0000ffff
+#define HFI_PROP_CROP_OFFSETS                                   0x03000105
+
+#define HFI_PROP_SESSION_PRIORITY                               0x03000106
+
+enum hfi_avc_profile_type {
+	HFI_AVC_PROFILE_BASELINE             = 0,
+	HFI_AVC_PROFILE_CONSTRAINED_BASELINE = 1,
+	HFI_AVC_PROFILE_MAIN                 = 2,
+	HFI_AVC_PROFILE_HIGH                 = 4,
+	HFI_AVC_PROFILE_CONSTRAINED_HIGH     = 17
+};
+
+enum hfi_hevc_profile_type {
+	HFI_H265_PROFILE_MAIN                  = 0,
+	HFI_H265_PROFILE_MAIN_STILL_PICTURE    = 1,
+	HFI_H265_PROFILE_MAIN_10               = 2,
+	HFI_H265_PROFILE_MAIN_10_STILL_PICTURE = 3,
+};
+
+enum hfi_vp9_profile_type {
+	HFI_VP9_PROFILE_0 = 0,
+	HFI_VP9_PROFILE_1 = 1,
+	HFI_VP9_PROFILE_2 = 2,
+	HFI_VP9_PROFILE_3 = 3,
+};
+
+enum hfi_mpeg2_profile_type {
+	HFI_MP2_PROFILE_SIMPLE = 0,
+	HFI_MP2_PROFILE_MAIN   = 1,
+};
+
+enum hfi_av1_profile_type {
+	HFI_AV1_PROFILE_MAIN = 0,
+	HFI_AV1_PROFILE_HIGH = 1,
+	HFI_AV1_PROFILE_PROF = 2,
+};
+
+#define HFI_PROP_PROFILE                                        0x03000107
+
+enum hfi_avc_level_type {
+	HFI_AVC_LEVEL_1_0 = 0,
+	HFI_AVC_LEVEL_1B  = 1,
+	HFI_AVC_LEVEL_1_1 = 2,
+	HFI_AVC_LEVEL_1_2 = 3,
+	HFI_AVC_LEVEL_1_3 = 4,
+	HFI_AVC_LEVEL_2_0 = 5,
+	HFI_AVC_LEVEL_2_1 = 6,
+	HFI_AVC_LEVEL_2_2 = 7,
+	HFI_AVC_LEVEL_3_0 = 8,
+	HFI_AVC_LEVEL_3_1 = 9,
+	HFI_AVC_LEVEL_3_2 = 10,
+	HFI_AVC_LEVEL_4_0 = 11,
+	HFI_AVC_LEVEL_4_1 = 12,
+	HFI_AVC_LEVEL_4_2 = 13,
+	HFI_AVC_LEVEL_5_0 = 14,
+	HFI_AVC_LEVEL_5_1 = 15,
+	HFI_AVC_LEVEL_5_2 = 16,
+	HFI_AVC_LEVEL_6_0 = 17,
+	HFI_AVC_LEVEL_6_1 = 18,
+	HFI_AVC_LEVEL_6_2 = 19,
+};
+
+enum hfi_hevc_level_type {
+	HFI_H265_LEVEL_1   = 0,
+	HFI_H265_LEVEL_2   = 1,
+	HFI_H265_LEVEL_2_1 = 2,
+	HFI_H265_LEVEL_3   = 3,
+	HFI_H265_LEVEL_3_1 = 4,
+	HFI_H265_LEVEL_4   = 5,
+	HFI_H265_LEVEL_4_1 = 6,
+	HFI_H265_LEVEL_5   = 7,
+	HFI_H265_LEVEL_5_1 = 8,
+	HFI_H265_LEVEL_5_2 = 9,
+	HFI_H265_LEVEL_6   = 10,
+	HFI_H265_LEVEL_6_1 = 11,
+	HFI_H265_LEVEL_6_2 = 12,
+};
+
+enum hfi_vp9_level_type {
+	HFI_VP9_LEVEL_1_0 = 0,
+	HFI_VP9_LEVEL_1_1 = 1,
+	HFI_VP9_LEVEL_2_0 = 2,
+	HFI_VP9_LEVEL_2_1 = 3,
+	HFI_VP9_LEVEL_3_0 = 4,
+	HFI_VP9_LEVEL_3_1 = 5,
+	HFI_VP9_LEVEL_4_0 = 6,
+	HFI_VP9_LEVEL_4_1 = 7,
+	HFI_VP9_LEVEL_5_0 = 8,
+	HFI_VP9_LEVEL_5_1 = 9,
+	HFI_VP9_LEVEL_6_0 = 10,
+	HFI_VP9_LEVEL_6_1 = 11,
+};
+
+enum hfi_mpeg2_level_type {
+	HFI_MP2_LEVEL_LOW       = 0,
+	HFI_MP2_LEVEL_MAIN      = 1,
+	HFI_MP2_LEVEL_HIGH_1440 = 2,
+	HFI_MP2_LEVEL_HIGH      = 3,
+};
+
+enum hfi_av1_level_type {
+	HFI_AV1_LEVEL_2_0 = 0,
+	HFI_AV1_LEVEL_2_1 = 1,
+	HFI_AV1_LEVEL_2_2 = 2,
+	HFI_AV1_LEVEL_2_3 = 3,
+	HFI_AV1_LEVEL_3_0 = 4,
+	HFI_AV1_LEVEL_3_1 = 5,
+	HFI_AV1_LEVEL_3_2 = 6,
+	HFI_AV1_LEVEL_3_3 = 7,
+	HFI_AV1_LEVEL_4_0 = 8,
+	HFI_AV1_LEVEL_4_1 = 9,
+	HFI_AV1_LEVEL_4_2 = 10,
+	HFI_AV1_LEVEL_4_3 = 11,
+	HFI_AV1_LEVEL_5_0 = 12,
+	HFI_AV1_LEVEL_5_1 = 13,
+	HFI_AV1_LEVEL_5_2 = 14,
+	HFI_AV1_LEVEL_5_3 = 15,
+	HFI_AV1_LEVEL_6_0 = 16,
+	HFI_AV1_LEVEL_6_1 = 17,
+	HFI_AV1_LEVEL_6_2 = 18,
+	HFI_AV1_LEVEL_6_3 = 19,
+	HFI_AV1_LEVEL_7_0 = 20,
+	HFI_AV1_LEVEL_7_1 = 21,
+	HFI_AV1_LEVEL_7_2 = 22,
+	HFI_AV1_LEVEL_7_3 = 23,
+	HFI_AV1_LEVEL_MAX = 31,
+};
+
+enum hfi_codec_level_type {
+	HFI_LEVEL_NONE = 0xFFFFFFFF,
+};
+
+#define HFI_PROP_LEVEL                                          0x03000108
+
+enum hfi_hevc_tier_type {
+	HFI_H265_TIER_MAIN = 0,
+	HFI_H265_TIER_HIGH = 1,
+};
+
+enum hfi_av1_tier_type {
+	HFI_AV1_TIER_MAIN = 0,
+	HFI_AV1_TIER_HIGH = 1,
+};
+
+#define HFI_PROP_TIER                                           0x03000109
+
+#define HFI_PROP_STAGE                                          0x0300010a
+
+#define HFI_PROP_PIPE                                           0x0300010b
+
+#define HFI_PROP_FRAME_RATE                                     0x0300010c
+
+#define HFI_BITMASK_CONCEAL_LUMA       0x000003ff
+#define HFI_BITMASK_CONCEAL_CB         0x000ffC00
+#define HFI_BITMASK_CONCEAL_CR         0x3ff00000
+#define HFI_PROP_CONCEAL_COLOR_8BIT                             0x0300010d
+
+#define HFI_BITMASK_CONCEAL_LUMA       0x000003ff
+#define HFI_BITMASK_CONCEAL_CB         0x000ffC00
+#define HFI_BITMASK_CONCEAL_CR         0x3ff00000
+#define HFI_PROP_CONCEAL_COLOR_10BIT                            0x0300010e
+
+#define HFI_BITMASK_LUMA_BIT_DEPTH     0xffff0000
+#define HFI_BITMASK_CHROMA_BIT_DEPTH   0x0000ffff
+#define HFI_PROP_LUMA_CHROMA_BIT_DEPTH                          0x0300010f
+
+#define HFI_BITMASK_FRAME_MBS_ONLY_FLAG           0x00000001
+#define HFI_BITMASK_MB_ADAPTIVE_FRAME_FIELD_FLAG  0x00000002
+#define HFI_PROP_CODED_FRAMES                                   0x03000120
+
+#define HFI_PROP_CABAC_SESSION                                  0x03000121
+
+#define HFI_PROP_8X8_TRANSFORM                                  0x03000122
+
+#define HFI_PROP_BUFFER_HOST_MAX_COUNT                          0x03000123
+
+#define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT                     0x03000124
+
+#define HFI_PROP_BUFFER_MAXDPB_COUNT                            0x03000125
+
+#define HFI_PROP_BUFFER_MAX_NUM_REFERENCE                       0x03000126
+
+#define HFI_PROP_MAX_NUM_REORDER_FRAMES                         0x03000127
+
+#define HFI_PROP_PIC_ORDER_CNT_TYPE                             0x03000128
+
+enum hfi_deblock_mode {
+	HFI_DEBLOCK_ALL_BOUNDARY              = 0x0,
+	HFI_DEBLOCK_DISABLE                   = 0x1,
+	HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY = 0x2,
+};
+
+#define HFI_PROP_DEBLOCKING_MODE                                0x03000129
+
+enum hfi_rate_control {
+	HFI_RC_VBR_CFR        = 0x00000000,
+	HFI_RC_CBR_CFR        = 0x00000001,
+	HFI_RC_CQ             = 0x00000002,
+	HFI_RC_OFF            = 0x00000003,
+	HFI_RC_CBR_VFR        = 0x00000004,
+	HFI_RC_LOSSLESS       = 0x00000005,
+};
+
+#define HFI_PROP_RATE_CONTROL                                   0x0300012a
+
+#define HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL                  0x0300012b
+
+#define HFI_PROP_CONTENT_ADAPTIVE_CODING                        0x0300012c
+
+#define HFI_PROP_BITRATE_BOOST                                  0x0300012d
+
+#define HFI_BITMASK_QP_I          0x000000ff
+#define HFI_BITMASK_QP_P          0x0000ff00
+#define HFI_BITMASK_QP_B          0x00ff0000
+#define HFI_BITMASK_QP_ENABLE     0x0f000000
+#define HFI_BITMASK_QP_LAYERS     0xf0000000
+#define HFI_PROP_QP_PACKED                                      0x0300012e
+
+#define HFI_PROP_MIN_QP_PACKED                                  0x0300012f
+
+#define HFI_PROP_MAX_QP_PACKED                                  0x03000130
+
+#define HFI_PROP_IR_RANDOM_PERIOD                               0x03000131
+
+#define HFI_PROP_MULTI_SLICE_MB_COUNT                           0x03000132
+
+#define HFI_PROP_MULTI_SLICE_BYTES_COUNT                        0x03000133
+
+#define HFI_PROP_LTR_COUNT                                      0x03000134
+
+#define HFI_PROP_LTR_MARK                                       0x03000135
+
+#define HFI_PROP_LTR_USE                                        0x03000136
+
+#define HFI_PROP_LTR_MARK_USE_DETAILS                           0x03000137
+
+enum hfi_layer_encoding_type {
+	HFI_HIER_P_SLIDING_WINDOW = 0x1,
+	HFI_HIER_P_HYBRID_LTR     = 0x2,
+	HFI_HIER_B                = 0x3,
+};
+
+#define HFI_PROP_LAYER_ENCODING_TYPE                            0x03000138
+
+#define HFI_PROP_LAYER_COUNT                                    0x03000139
+
+enum hfi_chromaqp_offset_mode {
+	HFI_ADAPTIVE_CHROMAQP_OFFSET = 0x0,
+	HFI_FIXED_CHROMAQP_OFFSET = 0x1,
+};
+
+#define HFI_BITMASK_CHROMA_CB_OFFSET     0x0000ffff
+#define HFI_BITMASK_CHROMA_CR_OFFSET     0xffff0000
+#define HFI_PROP_CHROMA_QP_OFFSET                               0x0300013a
+
+#define HFI_PROP_TOTAL_BITRATE                                  0x0300013b
+
+#define HFI_PROP_BITRATE_LAYER1                                 0x0300013c
+
+#define HFI_PROP_BITRATE_LAYER2                                 0x0300013d
+
+#define HFI_PROP_BITRATE_LAYER3                                 0x0300013e
+
+#define HFI_PROP_BITRATE_LAYER4                                 0x0300013f
+
+#define HFI_PROP_BITRATE_LAYER5                                 0x03000140
+
+#define HFI_PROP_BITRATE_LAYER6                                 0x03000141
+
+#define HFI_PROP_BASELAYER_PRIORITYID                           0x03000142
+
+#define HFI_PROP_CONSTANT_QUALITY                               0x03000143
+
+#define HFI_PROP_HEIC_GRID_ENABLE                               0x03000144
+
+enum hfi_syncframe_request_mode {
+	HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR           = 0x00000001,
+	HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR       = 0x00000002,
+};
+
+#define HFI_PROP_REQUEST_SYNC_FRAME                             0x03000145
+
+#define HFI_PROP_MAX_GOP_FRAMES                                 0x03000146
+
+#define HFI_PROP_MAX_B_FRAMES                                   0x03000147
+
+enum hfi_quality_mode {
+	HFI_MODE_MAX_QUALITY = 0x1,
+	HFI_MODE_POWER_SAVE  = 0x2,
+};
+
+#define HFI_PROP_QUALITY_MODE                                   0x03000148
+
+enum hfi_seq_header_mode {
+	HFI_SEQ_HEADER_SEPERATE_FRAME         = 0x00000001,
+	HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME  = 0x00000002,
+	HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME = 0x00000004,
+	HFI_SEQ_HEADER_METADATA               = 0x00000008,
+};
+
+#define HFI_PROP_SEQ_HEADER_MODE                                0x03000149
+
+#define HFI_PROP_METADATA_SEQ_HEADER_NAL                        0x0300014a
+
+enum hfi_rotation {
+	HFI_ROTATION_NONE = 0x00000000,
+	HFI_ROTATION_90   = 0x00000001,
+	HFI_ROTATION_180  = 0x00000002,
+	HFI_ROTATION_270  = 0x00000003,
+};
+
+#define HFI_PROP_ROTATION                                       0x0300014b
+
+enum hfi_flip {
+	HFI_DISABLE_FLIP    = 0x00000000,
+	HFI_HORIZONTAL_FLIP = 0x00000001,
+	HFI_VERTICAL_FLIP   = 0x00000002,
+};
+
+#define HFI_PROP_FLIP                                           0x0300014c
+
+#define HFI_PROP_SCALAR                                         0x0300014d
+
+enum hfi_blur_types {
+	HFI_BLUR_NONE     = 0x00000000,
+	HFI_BLUR_EXTERNAL = 0x00000001,
+	HFI_BLUR_ADAPTIVE = 0x00000002,
+};
+
+#define HFI_PROP_BLUR_TYPES                                     0x0300014e
+
+#define HFI_BITMASK_BLUR_WIDTH        0xffff0000
+#define HFI_BITMASK_BLUR_HEIGHT       0x0000ffff
+#define HFI_PROP_BLUR_RESOLUTION                                0x0300014f
+
+#define HFI_BITMASK_SPS_ID            0x000000ff
+#define HFI_BITMASK_PPS_ID            0x0000ff00
+#define HFI_BITMASK_VPS_ID            0x00ff0000
+#define HFI_PROP_SEQUENCE_HEADER_IDS                            0x03000150
+
+#define HFI_PROP_AUD                                            0x03000151
+
+#define HFI_PROP_DPB_LUMA_CHROMA_MISR                           0x03000153
+
+#define HFI_PROP_OPB_LUMA_CHROMA_MISR                           0x03000154
+
+#define HFI_BITMASK_QP_I               0x000000ff
+#define HFI_BITMASK_QP_P               0x0000ff00
+#define HFI_BITMASK_QP_B               0x00ff0000
+#define HFI_BITMASK_QP_ENABLE          0x0f000000
+#define HFI_BITMASK_QP_LAYERS          0xf0000000
+#define HFI_PROP_SIGNAL_COLOR_INFO                              0x03000155
+
+enum hfi_interlace_info {
+	HFI_INTERLACE_INFO_NONE                = 0x00000000,
+	HFI_FRAME_PROGRESSIVE                  = 0x00000001,
+	HFI_FRAME_MBAFF                        = 0x00000002,
+	HFI_FRAME_INTERLEAVE_TOPFIELD_FIRST    = 0x00000004,
+	HFI_FRAME_INTERLEAVE_BOTTOMFIELD_FIRST = 0x00000008,
+	HFI_FRAME_INTERLACE_TOPFIELD_FIRST     = 0x00000010,
+	HFI_FRAME_INTERLACE_BOTTOMFIELD_FIRST  = 0x00000020,
+};
+
+#define HFI_PROP_INTERLACE_INFO                                 0x03000156
+
+#define HFI_PROP_CSC                                            0x03000157
+
+#define HFI_PROP_CSC_MATRIX                                     0x03000158
+
+#define HFI_PROP_CSC_BIAS                                       0x03000159
+
+#define HFI_PROP_CSC_LIMIT                                      0x0300015a
+
+#define HFI_PROP_DECODE_ORDER_OUTPUT                            0x0300015b
+
+#define HFI_PROP_TIMESTAMP                                      0x0300015c
+
+#define HFI_PROP_FRAMERATE_FROM_BITSTREAM                       0x0300015d
+
+#define HFI_PROP_SEI_RECOVERY_POINT                             0x0300015e
+
+#define HFI_PROP_CONEALED_MB_COUNT                              0x0300015f
+
+#define HFI_BITMASK_SAR_WIDTH        0xffff0000
+#define HFI_BITMASK_SAR_HEIGHT       0x0000ffff
+#define HFI_PROP_SAR_RESOLUTION                                 0x03000160
+
+#define HFI_PROP_HISTOGRAM_INFO                                 0x03000161
+
+enum hfi_picture_type {
+	HFI_PICTURE_IDR = 0x00000001,
+	HFI_PICTURE_P   = 0x00000002,
+	HFI_PICTURE_B   = 0x00000004,
+	HFI_PICTURE_I   = 0x00000008,
+	HFI_PICTURE_CRA = 0x00000010,
+	HFI_PICTURE_BLA = 0x00000020,
+	HFI_PICTURE_NOSHOW = 0x00000040,
+};
+
+#define HFI_PROP_PICTURE_TYPE                                   0x03000162
+
+#define HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR                   0x03000163
+
+#define HFI_PROP_SEI_CONTENT_LIGHT_LEVEL                        0x03000164
+
+#define HFI_PROP_SEI_HDR10PLUS_USERDATA                         0x03000165
+
+#define HFI_PROP_SEI_STREAM_USERDATA                            0x03000166
+
+#define HFI_PROP_EVA_STAT_INFO                                  0x03000167
+
+#define HFI_PROP_DEC_DEFAULT_HEADER                             0x03000168
+
+#define HFI_PROP_DEC_START_FROM_RAP_FRAME                       0x03000169
+
+#define HFI_PROP_NO_OUTPUT                                      0x0300016a
+
+#define HFI_PROP_BUFFER_TAG                                     0x0300016b
+
+#define HFI_PROP_BUFFER_MARK                                    0x0300016c
+
+#define HFI_PROP_SUBFRAME_OUTPUT                                0x0300016d
+
+#define HFI_PROP_ENC_QP_METADATA                                0x0300016e
+
+#define HFI_PROP_DEC_QP_METADATA                                0x0300016f
+
+#define HFI_PROP_SEI_FRAME_PACKING_ARRANGEMENT                  0x03000170
+
+#define HFI_PROP_SEI_PAN_SCAN_RECT                              0x03000171
+
+#define HFI_PROP_THUMBNAIL_MODE                                 0x03000172
+
+#define HFI_PROP_ROI_INFO                                       0x03000173
+
+#define HFI_PROP_WORST_COMPRESSION_RATIO                        0x03000174
+
+#define HFI_PROP_WORST_COMPLEXITY_FACTOR                        0x03000175
+
+#define HFI_PROP_VBV_DELAY                                      0x03000176
+
+#define HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME                       0x03000177
+
+#define HFI_BITMASK_RAW_WIDTH                           0xffff0000
+#define HFI_BITMASK_RAW_HEIGHT                          0x0000ffff
+#define HFI_PROP_RAW_RESOLUTION                                 0x03000178
+
+#define HFI_PROP_DPB_TAG_LIST                                   0x03000179
+
+#define HFI_PROP_DPB_LIST                                       0x0300017A
+
+enum hfi_nal_length_field_type {
+	HFI_NAL_LENGTH_STARTCODES           = 0,
+	HFI_NAL_LENGTH_SIZE_4               = 4,
+};
+
+#define HFI_PROP_NAL_LENGTH_FIELD                               0x0300017B
+
+#define HFI_PROP_TOTAL_PEAK_BITRATE                             0x0300017C
+
+#define HFI_PROP_MAINTAIN_MIN_QUALITY                           0x0300017D
+
+#define HFI_PROP_IR_CYCLIC_PERIOD                               0x0300017E
+
+#define HFI_PROP_ENABLE_SLICE_DELIVERY                          0x0300017F
+
+#define HFI_PROP_AV1_FILM_GRAIN_PRESENT                         0x03000180
+
+#define HFI_PROP_AV1_SUPER_BLOCK_ENABLED                        0x03000181
+
+#define HFI_PROP_AV1_OP_POINT                                   0x03000182
+
+#define HFI_PROP_SUBFRAME_INPUT                                 0x03000183
+
+#define HFI_PROP_OPB_ENABLE                                     0x03000184
+
+#define HFI_PROP_AV1_TILE_ROWS_COLUMNS                          0x03000187
+
+#define HFI_PROP_AV1_DRAP_CONFIG                                0x03000189
+
+enum hfi_saliency_type {
+	HFI_SALIENCY_NONE,
+	HFI_SALIENCY_TYPE0,
+};
+
+#define HFI_PROP_ROI_AS_SALIENCY_INFO                           0x0300018A
+
+#define HFI_PROP_FENCE                                          0x0300018B
+
+#define HFI_PROP_REQUEST_PREPROCESS                             0x0300018E
+
+#define HFI_PROP_UBWC_STRIDE_SCANLINE                           0x03000190
+
+#define HFI_PROP_TRANSCODING_STAT_INFO                          0x03000191
+
+#define HFI_PROP_DOLBY_RPU_METADATA                             0x03000192
+
+#define HFI_PROP_COMV_BUFFER_COUNT                              0x03000193
+
+#define HFI_PROP_DISABLE_VUI_TIMING_INFO                        0x03000194
+
+#define HFI_PROP_SLICE_DECODE                                   0x03000196
+
+#define HFI_PROP_AV1_UNIFORM_TILE_SPACING                       0x03000197
+
+#define HFI_PROP_ENC_RING_BIN_BUF                               0x0300019C
+
+/* u32 */
+enum hfi_fence_type {
+	HFI_SW_FENCE                      = 0x00000001,
+	HFI_SYNX_V2_FENCE                 = 0x00000002,
+};
+
+#define HFI_PROP_FENCE_TYPE                                     0x0300019D
+
+enum hfi_fence_direction_type {
+	HFI_FENCE_TX_ENABLE          = 0x00000001,
+	HFI_FENCE_RX_ENABLE          = 0x00000002,
+};
+
+#define HFI_PROP_FENCE_DIRECTION                                0x0300019E
+
+#define HFI_PROP_FENCE_ERROR_DATA_CORRUPT                       0x0300019F
+
+#define HFI_PROP_END                                            0x03FFFFFF
+
+#define HFI_SESSION_ERROR_BEGIN                                 0x04000000
+
+#define HFI_ERROR_UNKNOWN_SESSION                               0x04000001
+
+#define HFI_ERROR_MAX_SESSIONS                                  0x04000002
+
+#define HFI_ERROR_FATAL                                         0x04000003
+
+#define HFI_ERROR_INVALID_STATE                                 0x04000004
+
+#define HFI_ERROR_INSUFFICIENT_RESOURCES                        0x04000005
+
+#define HFI_ERROR_BUFFER_NOT_SET                                0x04000006
+
+#define HFI_ERROR_DRAP_CONFIG_EXCEED                            0x04000007
+
+#define HFI_SESSION_ERROR_END                                   0x04FFFFFF
+
+#define HFI_SYSTEM_ERROR_BEGIN                                  0x05000000
+
+#define HFI_SYS_ERROR_WD_TIMEOUT                                0x05000001
+
+#define HFI_SYS_ERROR_NOC                                       0x05000002
+
+#define HFI_SYS_ERROR_FATAL                                     0x05000003
+
+#define HFI_SYSTEM_ERROR_END                                    0x05FFFFFF
+
+#define HFI_INFORMATION_BEGIN                                   0x06000000
+
+#define HFI_INFO_UNSUPPORTED                                    0x06000001
+
+#define HFI_INFO_DATA_CORRUPT                                   0x06000002
+
+#define HFI_INFO_NEGATIVE_TIMESTAMP                             0x06000003
+
+#define HFI_INFO_BUFFER_OVERFLOW                                0x06000004
+
+#define HFI_INFO_VCODEC_RESET                                   0x06000005
+
+#define HFI_INFO_HFI_FLAG_DRAIN_LAST                            0x06000006
+
+#define HFI_INFO_HFI_FLAG_PSC_LAST                              0x06000007
+
+#define HFI_INFO_FENCE_SIGNAL_ERROR                             0x06000008
+
+#define HFI_INFORMATION_END                                     0x06FFFFFF
+
+#endif //__H_HFI_PROPERTY_H__
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 23/33] iris: vidc: add PIL functionality for video firmware
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (21 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 22/33] iris: vidc: hfi: defines HFI properties and enums Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 24/33] iris: vidc: add debug files Vikash Garodia
                   ` (12 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

Here is the implementation of loading/unloading fw in memory
via mdt loader. This also implements fw suspend and resume.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../media/platform/qcom/iris/vidc/inc/firmware.h   |  18 ++
 .../media/platform/qcom/iris/vidc/src/firmware.c   | 294 +++++++++++++++++++++
 2 files changed, 312 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/firmware.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/firmware.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/firmware.h b/drivers/media/platform/qcom/iris/vidc/inc/firmware.h
new file mode 100644
index 0000000..bd52180
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/firmware.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_FIRMWARE_H_
+#define _MSM_VIDC_FIRMWARE_H_
+
+struct msm_vidc_core;
+
+int fw_load(struct msm_vidc_core *core);
+int fw_unload(struct msm_vidc_core *core);
+int fw_suspend(struct msm_vidc_core *core);
+int fw_resume(struct msm_vidc_core *core);
+void fw_coredump(struct msm_vidc_core *core);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/firmware.c b/drivers/media/platform/qcom/iris/vidc/src/firmware.c
new file mode 100644
index 0000000..f420096
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/firmware.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/firmware.h>
+#include <linux/list.h>
+#include <linux/of_address.h>
+#include <linux/devcoredump.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/soc/qcom/mdt_loader.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/types.h>
+
+#include "firmware.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_platform.h"
+
+#define MAX_FIRMWARE_NAME_SIZE	128
+
+struct tzbsp_memprot {
+	u32 cp_start;
+	u32 cp_size;
+	u32 cp_nonpixel_start;
+	u32 cp_nonpixel_size;
+};
+
+enum tzbsp_video_state {
+	TZBSP_VIDEO_STATE_SUSPEND = 0,
+	TZBSP_VIDEO_STATE_RESUME = 1,
+	TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2,
+};
+
+static int protect_cp_mem(struct msm_vidc_core *core)
+{
+	struct tzbsp_memprot memprot;
+	int rc = 0;
+	struct context_bank_info *cb;
+
+	memprot.cp_start = 0x0;
+	memprot.cp_size = 0x0;
+	memprot.cp_nonpixel_start = 0x0;
+	memprot.cp_nonpixel_size = 0x0;
+
+	venus_hfi_for_each_context_bank(core, cb) {
+		if (cb->region == MSM_VIDC_NON_SECURE) {
+			memprot.cp_size = cb->addr_range.start;
+
+			d_vpr_h("%s: memprot.cp_size: %#x\n",
+				__func__, memprot.cp_size);
+		}
+
+		if (cb->region == MSM_VIDC_SECURE_NONPIXEL) {
+			memprot.cp_nonpixel_start = cb->addr_range.start;
+			memprot.cp_nonpixel_size = cb->addr_range.size;
+
+			d_vpr_h("%s: cp_nonpixel_start: %#x size: %#x\n",
+				__func__, memprot.cp_nonpixel_start,
+				memprot.cp_nonpixel_size);
+		}
+	}
+
+	rc = qcom_scm_mem_protect_video_var(memprot.cp_start,
+					    memprot.cp_size,
+					    memprot.cp_nonpixel_start,
+					    memprot.cp_nonpixel_size);
+	if (rc)
+		d_vpr_e("Failed to protect memory(%d)\n", rc);
+
+	return rc;
+}
+
+static int __load_fw_to_memory(struct platform_device *pdev,
+			       const char *fw_name)
+{
+	int rc = 0;
+	const struct firmware *firmware = NULL;
+	struct msm_vidc_core *core;
+	char firmware_name[MAX_FIRMWARE_NAME_SIZE] = { 0 };
+	struct device_node *node = NULL;
+	struct resource res = { 0 };
+	phys_addr_t phys = 0;
+	size_t res_size = 0;
+	ssize_t fw_size = 0;
+	void *virt = NULL;
+	int pas_id = 0;
+
+	if (!fw_name || !(*fw_name) || !pdev) {
+		d_vpr_e("%s: Invalid inputs\n", __func__);
+		return -EINVAL;
+	}
+	if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) {
+		d_vpr_e("%s: Invalid fw name\n", __func__);
+		return -EINVAL;
+	}
+
+	core = dev_get_drvdata(&pdev->dev);
+	if (!core) {
+		d_vpr_e("%s: core not found in device %s",
+			__func__, dev_name(&pdev->dev));
+		return -EINVAL;
+	}
+	scnprintf(firmware_name, ARRAY_SIZE(firmware_name), "%s.mbn", fw_name);
+
+	pas_id = core->platform->data.pas_id;
+
+	node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+	if (!node) {
+		d_vpr_e("%s: failed to read \"memory-region\"\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = of_address_to_resource(node, 0, &res);
+	if (rc) {
+		d_vpr_e("%s: failed to read \"memory-region\", error %d\n",
+			__func__, rc);
+		goto exit;
+	}
+	phys = res.start;
+	res_size = (size_t)resource_size(&res);
+
+	rc = request_firmware(&firmware, firmware_name, &pdev->dev);
+	if (rc) {
+		d_vpr_e("%s: failed to request fw \"%s\", error %d\n",
+			__func__, firmware_name, rc);
+		goto exit;
+	}
+
+	fw_size = qcom_mdt_get_size(firmware);
+	if (fw_size < 0 || res_size < (size_t)fw_size) {
+		rc = -EINVAL;
+		d_vpr_e("%s: out of bound fw image fw size: %ld, res_size: %lu",
+			__func__, fw_size, res_size);
+		goto exit;
+	}
+
+	virt = memremap(phys, res_size, MEMREMAP_WC);
+	if (!virt) {
+		d_vpr_e("%s: failed to remap fw memory phys %pa[p]\n",
+			__func__, &phys);
+		return -ENOMEM;
+	}
+
+	/* prevent system suspend during fw_load */
+	pm_stay_awake(pdev->dev.parent);
+	rc = qcom_mdt_load(&pdev->dev, firmware, firmware_name,
+			   pas_id, virt, phys, res_size, NULL);
+	pm_relax(pdev->dev.parent);
+	if (rc) {
+		d_vpr_e("%s: error %d loading fw \"%s\"\n",
+			__func__, rc, firmware_name);
+		goto exit;
+	}
+	rc = qcom_scm_pas_auth_and_reset(pas_id);
+	if (rc) {
+		d_vpr_e("%s: error %d authenticating fw \"%s\"\n",
+			__func__, rc, firmware_name);
+		goto exit;
+	}
+
+	memunmap(virt);
+	release_firmware(firmware);
+	d_vpr_h("%s: firmware \"%s\" loaded successfully\n",
+		__func__, firmware_name);
+
+	return pas_id;
+
+exit:
+	if (virt)
+		memunmap(virt);
+	if (firmware)
+		release_firmware(firmware);
+
+	return rc;
+}
+
+int fw_load(struct msm_vidc_core *core)
+{
+	int rc;
+
+	if (!core->resource->fw_cookie) {
+		core->resource->fw_cookie = __load_fw_to_memory(core->pdev,
+								core->platform->data.fwname);
+		if (core->resource->fw_cookie <= 0) {
+			d_vpr_e("%s: firmware download failed %d\n",
+				__func__, core->resource->fw_cookie);
+			core->resource->fw_cookie = 0;
+			return -ENOMEM;
+		}
+	}
+
+	rc = protect_cp_mem(core);
+	if (rc) {
+		d_vpr_e("%s: protect memory failed\n", __func__);
+		goto fail_protect_mem;
+	}
+
+	return rc;
+
+fail_protect_mem:
+	if (core->resource->fw_cookie)
+		qcom_scm_pas_shutdown(core->resource->fw_cookie);
+	core->resource->fw_cookie = 0;
+	return rc;
+}
+
+int fw_unload(struct msm_vidc_core *core)
+{
+	int ret;
+
+	if (!core->resource->fw_cookie)
+		return -EINVAL;
+
+	ret = qcom_scm_pas_shutdown(core->resource->fw_cookie);
+	if (ret)
+		d_vpr_e("Firmware unload failed rc=%d\n", ret);
+
+	core->resource->fw_cookie = 0;
+
+	return ret;
+}
+
+int fw_suspend(struct msm_vidc_core *core)
+{
+	return qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
+}
+
+int fw_resume(struct msm_vidc_core *core)
+{
+	return qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0);
+}
+
+void fw_coredump(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+	struct device_node *node = NULL;
+	struct resource res = {0};
+	phys_addr_t mem_phys = 0;
+	size_t res_size = 0;
+	void *mem_va = NULL;
+	char *data = NULL, *dump = NULL;
+	u64 total_size;
+
+	pdev = core->pdev;
+
+	node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+	if (!node) {
+		d_vpr_e("%s: DT error getting \"memory-region\" property\n",
+			__func__);
+		return;
+	}
+
+	rc = of_address_to_resource(node, 0, &res);
+	if (rc) {
+		d_vpr_e("%s: error %d while getting \"memory-region\" resource\n",
+			__func__, rc);
+		return;
+	}
+
+	mem_phys = res.start;
+	res_size = (size_t)resource_size(&res);
+
+	mem_va = memremap(mem_phys, res_size, MEMREMAP_WC);
+	if (!mem_va) {
+		d_vpr_e("%s: unable to remap firmware memory\n", __func__);
+		return;
+	}
+	total_size = res_size + TOTAL_QSIZE + ALIGNED_SFR_SIZE;
+
+	data = vmalloc(total_size);
+	if (!data) {
+		memunmap(mem_va);
+		return;
+	}
+	dump = data;
+
+	/* copy firmware dump */
+	memcpy(data, mem_va, res_size);
+	memunmap(mem_va);
+
+	/* copy queues(cmd, msg, dbg) dump(along with headers) */
+	data += res_size;
+	memcpy(data, (char *)core->iface_q_table.align_virtual_addr, TOTAL_QSIZE);
+
+	/* copy sfr dump */
+	data += TOTAL_QSIZE;
+	memcpy(data, (char *)core->sfr.align_virtual_addr, ALIGNED_SFR_SIZE);
+
+	dev_coredumpv(&pdev->dev, dump, total_size, GFP_KERNEL);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 24/33] iris: vidc: add debug files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (22 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 23/33] iris: vidc: add PIL functionality for video firmware Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-31 21:31   ` Krzysztof Kozlowski
  2023-07-28 13:23 ` [PATCH 25/33] iris: platform: add platform files Vikash Garodia
                   ` (11 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

this implements the debugging framework.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   | 186 +++++++
 .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   | 581 +++++++++++++++++++++
 2 files changed, 767 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
 create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c

diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
new file mode 100644
index 0000000..ffced01
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+struct msm_vidc_core;
+struct msm_vidc_inst;
+
+#ifndef VIDC_DBG_LABEL
+#define VIDC_DBG_LABEL "msm_vidc"
+#endif
+
+/* Allow only 6 prints/sec */
+#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ)
+#define VIDC_DBG_SESSION_RATELIMIT_BURST 6
+
+#define VIDC_DBG_TAG_INST VIDC_DBG_LABEL ": %4s: %s: "
+#define VIDC_DBG_TAG_CORE VIDC_DBG_LABEL ": %4s: %08x: %s: "
+#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: "
+#define DEFAULT_SID ((u32)-1)
+
+#ifndef MSM_VIDC_EMPTY_BRACE
+#define MSM_VIDC_EMPTY_BRACE {},
+#endif
+
+extern unsigned int msm_vidc_debug;
+extern unsigned int msm_fw_debug;
+extern bool msm_vidc_fw_dump;
+
+/* do not modify the log message as it is used in test scripts */
+#define FMT_STRING_SET_CTRL \
+	"%s: state %s, name %s, id 0x%x value %d\n"
+#define FMT_STRING_STATE_CHANGE \
+	"%s: state changed to %s from %s\n"
+#define FMT_STRING_MSG_SFR \
+	"SFR Message from FW: %s\n"
+#define FMT_STRING_FAULT_HANDLER \
+	"%s: faulting address: %lx\n"
+#define FMT_STRING_SET_CAP \
+	"set cap: name: %24s, cap value: %#10x, hfi: %#10llx\n"
+
+/* To enable messages OR these values and
+ * echo the result to debugfs file.
+ *
+ * To enable all messages set msm_vidc_debug = 0x101F
+ */
+
+enum vidc_msg_prio_drv {
+	VIDC_ERR        = 0x00000001,
+	VIDC_HIGH       = 0x00000002,
+	VIDC_LOW        = 0x00000004,
+	VIDC_PERF       = 0x00000008,
+	VIDC_PKT        = 0x00000010,
+	VIDC_BUS        = 0x00000020,
+	VIDC_STAT       = 0x00000040,
+	VIDC_ENCODER    = 0x00000100,
+	VIDC_DECODER    = 0x00000200,
+	VIDC_PRINTK     = 0x10000000,
+	VIDC_FTRACE     = 0x20000000,
+};
+
+enum vidc_msg_prio_fw {
+	FW_LOW          = 0x00000001,
+	FW_MED          = 0x00000002,
+	FW_HIGH         = 0x00000004,
+	FW_ERROR        = 0x00000008,
+	FW_FATAL        = 0x00000010,
+	FW_PERF         = 0x00000020,
+	FW_CACHE_LOW    = 0x00000100,
+	FW_CACHE_MED    = 0x00000200,
+	FW_CACHE_HIGH   = 0x00000400,
+	FW_CACHE_ERROR  = 0x00000800,
+	FW_CACHE_FATAL  = 0x00001000,
+	FW_CACHE_PERF   = 0x00002000,
+	FW_PRINTK       = 0x10000000,
+	FW_FTRACE       = 0x20000000,
+};
+
+#define DRV_LOG        (VIDC_ERR | VIDC_PRINTK)
+#define DRV_LOGSHIFT   (0)
+#define DRV_LOGMASK    (0x0FFFFFFF)
+
+#define FW_LOG         (FW_ERROR | FW_FATAL | FW_PRINTK)
+#define FW_LOGSHIFT    (0)
+#define FW_LOGMASK     (0x0FFFFFFF)
+
+#define dprintk_inst(__level, __level_str, inst, __fmt, ...) \
+	do { \
+		if (inst && (msm_vidc_debug & (__level))) { \
+			pr_info(VIDC_DBG_TAG_INST __fmt, \
+				__level_str, \
+				inst->debug_str, \
+				##__VA_ARGS__); \
+		} \
+	} while (0)
+
+#define i_vpr_e(inst, __fmt, ...) dprintk_inst(VIDC_ERR,  "err ", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_i(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_h(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_l(inst, __fmt, ...) dprintk_inst(VIDC_LOW,  "low ", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_p(inst, __fmt, ...) dprintk_inst(VIDC_PERF, "perf", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_t(inst, __fmt, ...) dprintk_inst(VIDC_PKT,  "pkt ", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_b(inst, __fmt, ...) dprintk_inst(VIDC_BUS,  "bus ", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_s(inst, __fmt, ...) dprintk_inst(VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
+
+#define i_vpr_hp(inst, __fmt, ...) \
+	dprintk_inst(VIDC_HIGH | VIDC_PERF, "high", inst, __fmt, ##__VA_ARGS__)
+#define i_vpr_hs(inst, __fmt, ...) \
+	dprintk_inst(VIDC_HIGH | VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
+
+#define dprintk_core(__level, __level_str, __fmt, ...) \
+	do { \
+		if (msm_vidc_debug & (__level)) { \
+			pr_info(VIDC_DBG_TAG_CORE __fmt, \
+				__level_str, \
+				DEFAULT_SID, \
+				"codec", \
+				##__VA_ARGS__); \
+		} \
+	} while (0)
+
+#define d_vpr_e(__fmt, ...) dprintk_core(VIDC_ERR,  "err ", __fmt, ##__VA_ARGS__)
+#define d_vpr_h(__fmt, ...) dprintk_core(VIDC_HIGH, "high", __fmt, ##__VA_ARGS__)
+#define d_vpr_l(__fmt, ...) dprintk_core(VIDC_LOW,  "low ", __fmt, ##__VA_ARGS__)
+#define d_vpr_p(__fmt, ...) dprintk_core(VIDC_PERF, "perf", __fmt, ##__VA_ARGS__)
+#define d_vpr_t(__fmt, ...) dprintk_core(VIDC_PKT,  "pkt ", __fmt, ##__VA_ARGS__)
+#define d_vpr_b(__fmt, ...) dprintk_core(VIDC_BUS,  "bus ", __fmt, ##__VA_ARGS__)
+#define d_vpr_s(__fmt, ...) dprintk_core(VIDC_STAT, "stat", __fmt, ##__VA_ARGS__)
+#define d_vpr_hs(__fmt, ...) \
+	dprintk_core(VIDC_HIGH | VIDC_STAT, "high", __fmt, ##__VA_ARGS__)
+
+#define dprintk_ratelimit(__level, __level_str, __fmt, ...) \
+	do { \
+		if (msm_vidc_check_ratelimit()) { \
+			dprintk_core(__level, __level_str, __fmt, ##__VA_ARGS__); \
+		} \
+	} while (0)
+
+#define dprintk_firmware(__level, __fmt, ...)	\
+	do { \
+		if ((msm_fw_debug & (__level)) & FW_PRINTK) { \
+			pr_info(FW_DBG_TAG __fmt, \
+				"fw", \
+				##__VA_ARGS__); \
+		} \
+	} while (0)
+
+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,
+};
+
+enum msm_vidc_bug_on_error {
+	MSM_VIDC_BUG_ON_FATAL             = BIT(0),
+	MSM_VIDC_BUG_ON_NOC               = BIT(1),
+	MSM_VIDC_BUG_ON_WD_TIMEOUT        = BIT(2),
+};
+
+struct dentry *msm_vidc_debugfs_init_drv(void);
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+					  struct dentry *parent);
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+			     enum msm_vidc_debugfs_event e);
+int msm_vidc_check_ratelimit(void);
+
+static inline bool is_stats_enabled(void)
+{
+	return !!(msm_vidc_debug & VIDC_STAT);
+}
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
new file mode 100644
index 0000000..489e8dc
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+
+#define MAX_DEBUG_LEVEL_STRING_LEN 15
+#define MSM_VIDC_MIN_STATS_DELAY_MS     200
+#define MSM_VIDC_MAX_STATS_DELAY_MS     10000
+
+unsigned int msm_vidc_debug = DRV_LOG;
+unsigned int msm_fw_debug = FW_LOG;
+
+static int debug_level_set_drv(const char *val,
+			       const struct kernel_param *kp)
+{
+	struct msm_vidc_core *core = NULL;
+	unsigned int dvalue;
+	int ret;
+
+	if (!kp || !kp->arg || !val) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(val, 0, &dvalue);
+	if (ret)
+		return ret;
+
+	msm_vidc_debug = dvalue;
+
+	core = *(struct msm_vidc_core **)kp->arg;
+
+	if (!core) {
+		d_vpr_e("%s: Invalid core/capabilities\n", __func__);
+		return 0;
+	}
+
+	/* check if driver is more than default level */
+	if ((dvalue & DRV_LOGMASK) & ~(DRV_LOG)) {
+		core->capabilities[HW_RESPONSE_TIMEOUT].value = 4 * HW_RESPONSE_TIMEOUT_VALUE;
+		core->capabilities[SW_PC_DELAY].value         = 4 * SW_PC_DELAY_VALUE;
+		core->capabilities[FW_UNLOAD_DELAY].value     = 4 * FW_UNLOAD_DELAY_VALUE;
+	} else {
+		/* reset timeout values, if user reduces the logging */
+		core->capabilities[HW_RESPONSE_TIMEOUT].value = HW_RESPONSE_TIMEOUT_VALUE;
+		core->capabilities[SW_PC_DELAY].value         = SW_PC_DELAY_VALUE;
+		core->capabilities[FW_UNLOAD_DELAY].value     = FW_UNLOAD_DELAY_VALUE;
+	}
+
+	d_vpr_h("timeout for driver: hw_response %u, sw_pc %u, fw_unload %u, debug_level %#x\n",
+		core->capabilities[HW_RESPONSE_TIMEOUT].value,
+		core->capabilities[SW_PC_DELAY].value,
+		core->capabilities[FW_UNLOAD_DELAY].value,
+		msm_vidc_debug);
+
+	return 0;
+}
+
+static int debug_level_set_fw(const char *val,
+			      const struct kernel_param *kp)
+{
+	struct msm_vidc_core *core = NULL;
+	unsigned int dvalue;
+	int ret;
+
+	if (!kp || !kp->arg || !val) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(val, 0, &dvalue);
+	if (ret)
+		return ret;
+
+	msm_fw_debug = dvalue;
+
+	core = *(struct msm_vidc_core **)kp->arg;
+
+	if (!core) {
+		d_vpr_e("%s: Invalid core/capabilities\n", __func__);
+		return 0;
+	}
+
+	/* check if firmware is more than default level */
+	if ((dvalue & FW_LOGMASK) & ~(FW_LOG)) {
+		core->capabilities[HW_RESPONSE_TIMEOUT].value = 4 * HW_RESPONSE_TIMEOUT_VALUE;
+		core->capabilities[SW_PC_DELAY].value         = 4 * SW_PC_DELAY_VALUE;
+		core->capabilities[FW_UNLOAD_DELAY].value     = 4 * FW_UNLOAD_DELAY_VALUE;
+	} else {
+		/* reset timeout values, if user reduces the logging */
+		core->capabilities[HW_RESPONSE_TIMEOUT].value = HW_RESPONSE_TIMEOUT_VALUE;
+		core->capabilities[SW_PC_DELAY].value         = SW_PC_DELAY_VALUE;
+		core->capabilities[FW_UNLOAD_DELAY].value     = FW_UNLOAD_DELAY_VALUE;
+	}
+
+	d_vpr_h("timeout for firmware: hw_response %u, sw_pc %u, fw_unload %u, debug_level %#x\n",
+		core->capabilities[HW_RESPONSE_TIMEOUT].value,
+		core->capabilities[SW_PC_DELAY].value,
+		core->capabilities[FW_UNLOAD_DELAY].value,
+		msm_fw_debug);
+
+	return 0;
+}
+
+static int debug_level_get_drv(char *buffer, const struct kernel_param *kp)
+{
+	return scnprintf(buffer, PAGE_SIZE, "%#x", msm_vidc_debug);
+}
+
+static int debug_level_get_fw(char *buffer, const struct kernel_param *kp)
+{
+	return scnprintf(buffer, PAGE_SIZE, "%#x", msm_fw_debug);
+}
+
+static const struct kernel_param_ops msm_vidc_debug_fops = {
+	.set = debug_level_set_drv,
+	.get = debug_level_get_drv,
+};
+
+static const struct kernel_param_ops msm_fw_debug_fops = {
+	.set = debug_level_set_fw,
+	.get = debug_level_get_fw,
+};
+
+static int fw_dump_set(const char *val, const struct kernel_param *kp)
+{
+	unsigned int dvalue;
+	int ret;
+
+	if (!kp || !kp->arg || !val) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(val, 0, &dvalue);
+	if (ret)
+		return ret;
+
+	msm_vidc_fw_dump = dvalue;
+
+	d_vpr_h("fw dump %s\n", msm_vidc_fw_dump ? "Enabled" : "Disabled");
+
+	return 0;
+}
+
+static int fw_dump_get(char *buffer, const struct kernel_param *kp)
+{
+	return scnprintf(buffer, PAGE_SIZE, "%#x", msm_vidc_fw_dump);
+}
+
+static const struct kernel_param_ops msm_vidc_fw_dump_fops = {
+	.set = fw_dump_set,
+	.get = fw_dump_get,
+};
+
+module_param_cb(msm_vidc_debug, &msm_vidc_debug_fops, &g_core, 0644);
+module_param_cb(msm_fw_debug, &msm_fw_debug_fops, &g_core, 0644);
+module_param_cb(msm_vidc_fw_dump, &msm_vidc_fw_dump_fops, &g_core, 0644);
+
+bool msm_vidc_fw_dump = !true;
+EXPORT_SYMBOL(msm_vidc_fw_dump);
+
+#define MAX_DBG_BUF_SIZE 4096
+
+struct core_inst_pair {
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+};
+
+/* debug fs support */
+
+static u32 write_str(char *buffer, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	u32 len;
+
+	va_start(args, fmt);
+	len = vscnprintf(buffer, size, fmt, args);
+	va_end(args);
+	return len;
+}
+
+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;
+	char *cur, *end, *dbuf = NULL;
+	ssize_t len = 0;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, core);
+		return 0;
+	}
+
+	dbuf = vzalloc(MAX_DBG_BUF_SIZE);
+	if (!dbuf) {
+		d_vpr_e("%s: allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+
+	cur += write_str(cur, end - cur, "Core state: %d\n", core->state);
+
+	cur += write_str(cur, end - cur,
+		"FW version : %s\n", core->fw_version);
+	cur += write_str(cur, end - cur,
+		"register_base: 0x%x\n", core->resource->register_base_addr);
+	cur += write_str(cur, end - cur, "irq: %u\n", core->resource->irq);
+
+	len = simple_read_from_buffer(buf, count, ppos, dbuf, cur - dbuf);
+
+	vfree(dbuf);
+	return len;
+}
+
+static const struct file_operations core_info_fops = {
+	.open = simple_open,
+	.read = core_info_read,
+};
+
+static ssize_t stats_delay_write_ms(struct file *filp, const char __user *buf,
+				    size_t count, loff_t *ppos)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = filp->private_data;
+	char kbuf[MAX_DEBUG_LEVEL_STRING_LEN] = {0};
+	u32 delay_ms = 0;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, core);
+		return 0;
+	}
+
+	/* filter partial writes and invalid commands */
+	if (*ppos != 0 || count >= sizeof(kbuf) || count == 0) {
+		d_vpr_e("returning error - pos %lld, count %lu\n", *ppos, count);
+		rc = -EINVAL;
+	}
+
+	rc = simple_write_to_buffer(kbuf, sizeof(kbuf) - 1, ppos, buf, count);
+	if (rc < 0) {
+		d_vpr_e("%s: User memory fault\n", __func__);
+		rc = -EFAULT;
+		goto exit;
+	}
+
+	rc = kstrtoint(kbuf, 0, &delay_ms);
+	if (rc) {
+		d_vpr_e("returning error err %d\n", rc);
+		rc = -EINVAL;
+		goto exit;
+	}
+	delay_ms = clamp_t(u32, delay_ms, MSM_VIDC_MIN_STATS_DELAY_MS, MSM_VIDC_MAX_STATS_DELAY_MS);
+	core->capabilities[STATS_TIMEOUT_MS].value = delay_ms;
+	d_vpr_h("Stats delay is updated to - %d ms\n", delay_ms);
+
+exit:
+	return rc;
+}
+
+static ssize_t stats_delay_read_ms(struct file *file, char __user *buf,
+				   size_t count, loff_t *ppos)
+{
+	size_t len;
+	char kbuf[MAX_DEBUG_LEVEL_STRING_LEN];
+	struct msm_vidc_core *core = file->private_data;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, core);
+		return 0;
+	}
+
+	len = scnprintf(kbuf, sizeof(kbuf), "%u\n", core->capabilities[STATS_TIMEOUT_MS].value);
+	return simple_read_from_buffer(buf, count, ppos, kbuf, len);
+}
+
+static const struct file_operations stats_delay_fops = {
+	.open = simple_open,
+	.write = stats_delay_write_ms,
+	.read = stats_delay_read_ms,
+};
+
+struct dentry *msm_vidc_debugfs_init_drv(void)
+{
+	struct dentry *dir = NULL;
+
+	dir = debugfs_create_dir("msm_vidc", NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		goto failed_create_dir;
+	}
+
+	return dir;
+
+failed_create_dir:
+	debugfs_remove_recursive(dir);
+
+	return NULL;
+}
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core)
+{
+	struct dentry *dir = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	struct dentry *parent;
+
+	if (!core->debugfs_parent) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		goto failed_create_dir;
+	}
+	parent = core->debugfs_parent;
+
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core");
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		d_vpr_e("Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) {
+		d_vpr_e("debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+
+	if (!debugfs_create_file("stats_delay_ms", 0644, dir, core, &stats_delay_fops)) {
+		d_vpr_e("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)
+{
+	d_vpr_l("Open inode ptr: %pK\n", inode->i_private);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct core_inst_pair *idata = file->private_data;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+	char *cur, *end, *dbuf = NULL;
+	int i, j;
+	ssize_t len = 0;
+	struct v4l2_format *f;
+
+	if (!idata || !idata->core || !idata->inst) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, idata);
+		return 0;
+	}
+
+	core = idata->core;
+	inst = idata->inst;
+
+	inst = get_inst(core, inst->session_id);
+	if (!inst) {
+		d_vpr_h("%s: instance has become obsolete", __func__);
+		return 0;
+	}
+
+	dbuf = vzalloc(MAX_DBG_BUF_SIZE);
+	if (!dbuf) {
+		d_vpr_e("%s: allocation failed\n", __func__);
+		len = -ENOMEM;
+		goto failed_alloc;
+	}
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst,
+		inst->domain == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "core: %pK\n", inst->core);
+	cur += write_str(cur, end - cur, "height: %d\n", f->fmt.pix_mp.height);
+	cur += write_str(cur, end - cur, "width: %d\n", f->fmt.pix_mp.width);
+	cur += write_str(cur, end - cur, "fps: %d\n",
+			inst->capabilities[FRAME_RATE].value >> 16);
+	cur += write_str(cur, end - cur, "state: %d\n", inst->state);
+	cur += write_str(cur, end - cur, "-----------Formats-------------\n");
+	for (i = 0; i < MAX_PORT; i++) {
+		if (i != INPUT_PORT && i != OUTPUT_PORT)
+			continue;
+		f = &inst->fmts[i];
+		cur += write_str(cur, end - cur, "capability: %s\n",
+			i == INPUT_PORT ? "Output" : "Capture");
+		cur += write_str(cur, end - cur, "planes : %d\n",
+			f->fmt.pix_mp.num_planes);
+		cur += write_str(cur, end - cur,
+			"type: %s\n", i == INPUT_PORT ?
+			"Output" : "Capture");
+		cur += write_str(cur, end - cur, "count: %u\n",
+				inst->bufq[i].vb2q->num_buffers);
+
+		for (j = 0; j < f->fmt.pix_mp.num_planes; j++)
+			cur += write_str(cur, end - cur,
+				"size for plane %d: %u\n",
+				j, f->fmt.pix_mp.plane_fmt[j].sizeimage);
+
+		cur += write_str(cur, end - cur, "\n");
+	}
+	cur += write_str(cur, end - cur, "-------------------------------\n");
+	cur += write_str(cur, end - cur, "ETB Count: %d\n",
+		inst->debug_count.etb);
+	cur += write_str(cur, end - cur, "EBD Count: %d\n",
+		inst->debug_count.ebd);
+	cur += write_str(cur, end - cur, "FTB Count: %d\n",
+		inst->debug_count.ftb);
+	cur += write_str(cur, end - cur, "FBD Count: %d\n",
+		inst->debug_count.fbd);
+
+	len = simple_read_from_buffer(buf, count, ppos,
+				      dbuf, cur - dbuf);
+
+	vfree(dbuf);
+failed_alloc:
+	put_inst(inst);
+	return len;
+}
+
+static int inst_info_release(struct inode *inode, struct file *file)
+{
+	d_vpr_l("Release inode ptr: %pK\n", inode->i_private);
+	file->private_data = NULL;
+	return 0;
+}
+
+static const struct file_operations inst_info_fops = {
+	.open = inst_info_open,
+	.read = inst_info_read,
+	.release = inst_info_release,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, struct dentry *parent)
+{
+	struct dentry *dir = NULL, *info = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	struct core_inst_pair *idata = NULL;
+
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%d", inst->session_id);
+
+	idata = vzalloc(sizeof(*idata));
+	if (!idata) {
+		i_vpr_e(inst, "%s: allocation failed\n", __func__);
+		goto exit;
+	}
+
+	idata->core = inst->core;
+	idata->inst = inst;
+
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		i_vpr_e(inst,
+			"%s: Failed to create debugfs for msm_vidc\n",
+			__func__);
+		goto failed_create_dir;
+	}
+
+	info = debugfs_create_file("info", 0444, dir,
+				   idata, &inst_info_fops);
+	if (IS_ERR_OR_NULL(info)) {
+		i_vpr_e(inst, "%s: debugfs_create_file: fail\n",
+			__func__);
+		goto failed_create_file;
+	}
+
+	dir->d_inode->i_private = info->d_inode->i_private;
+	return dir;
+
+failed_create_file:
+	debugfs_remove_recursive(dir);
+	dir = NULL;
+failed_create_dir:
+	vfree(idata);
+exit:
+	return dir;
+}
+
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst)
+{
+	struct dentry *dentry = NULL;
+
+	if (!inst->debugfs_root)
+		return;
+
+	dentry = inst->debugfs_root;
+	if (dentry->d_inode) {
+		i_vpr_l(inst, "%s: Destroy %pK\n",
+			__func__, dentry->d_inode->i_private);
+		vfree(dentry->d_inode->i_private);
+		dentry->d_inode->i_private = NULL;
+	}
+	debugfs_remove_recursive(dentry);
+	inst->debugfs_root = NULL;
+}
+
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+			     enum msm_vidc_debugfs_event e)
+{
+	switch (e) {
+	case MSM_VIDC_DEBUGFS_EVENT_ETB:
+		inst->debug_count.etb++;
+		if (inst->debug_count.ebd &&
+		    inst->debug_count.ftb > inst->debug_count.fbd) {
+		}
+		break;
+	case MSM_VIDC_DEBUGFS_EVENT_EBD:
+		inst->debug_count.ebd++;
+		/*
+		 * Host needs to ensure FW at least have 2 buffers available always
+		 * one for HW processing and another for fw processing in parallel
+		 * to avoid FW starving for buffers
+		 */
+		if (inst->debug_count.etb < (inst->debug_count.ebd + 2)) {
+			i_vpr_p(inst,
+				"EBD: FW needs input buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n",
+				inst->debug_count.etb, inst->debug_count.ebd,
+				inst->debug_count.ftb, inst->debug_count.fbd);
+		}
+		if (inst->debug_count.fbd &&
+		    inst->debug_count.ftb < (inst->debug_count.fbd + 2))
+			i_vpr_p(inst,
+				"EBD: FW needs output buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n",
+				inst->debug_count.etb, inst->debug_count.ebd,
+				inst->debug_count.ftb, inst->debug_count.fbd);
+		break;
+	case MSM_VIDC_DEBUGFS_EVENT_FTB:
+		inst->debug_count.ftb++;
+		if (inst->debug_count.ebd &&
+		    inst->debug_count.etb > inst->debug_count.ebd) {
+		}
+		break;
+	case MSM_VIDC_DEBUGFS_EVENT_FBD:
+		inst->debug_count.fbd++;
+		/*
+		 * Host needs to ensure FW at least have 2 buffers available always
+		 * one for HW processing and another for fw processing in parallel
+		 * to avoid FW starving for buffers
+		 */
+		if (inst->debug_count.ftb < (inst->debug_count.fbd + 2)) {
+			i_vpr_p(inst,
+				"FBD: FW needs output buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n",
+				inst->debug_count.etb, inst->debug_count.ebd,
+				inst->debug_count.ftb, inst->debug_count.fbd);
+		}
+		if (inst->debug_count.ebd &&
+		    inst->debug_count.etb < (inst->debug_count.ebd + 2))
+			i_vpr_p(inst,
+				"FBD: FW needs input buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n",
+				inst->debug_count.etb, inst->debug_count.ebd,
+				inst->debug_count.ftb, inst->debug_count.fbd);
+		break;
+	default:
+		i_vpr_e(inst, "invalid event in debugfs: %d\n", e);
+		break;
+	}
+}
+
+int msm_vidc_check_ratelimit(void)
+{
+	static DEFINE_RATELIMIT_STATE(_rs,
+				VIDC_DBG_SESSION_RATELIMIT_INTERVAL,
+				VIDC_DBG_SESSION_RATELIMIT_BURST);
+	return __ratelimit(&_rs);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 25/33] iris: platform: add platform files
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (23 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 24/33] iris: vidc: add debug files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550 Vikash Garodia
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements adjust/set functions for different capabilities
supported by driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/platform/common/inc/msm_vidc_platform.h   |  305 +++
 .../iris/platform/common/src/msm_vidc_platform.c   | 2499 ++++++++++++++++++++
 2 files changed, 2804 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
 create mode 100644 drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c

diff --git a/drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h b/drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
new file mode 100644
index 0000000..87c9f2f
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
@@ -0,0 +1,305 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021,, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_PLATFORM_H_
+#define _MSM_VIDC_PLATFORM_H_
+
+#include <linux/platform_device.h>
+#include <media/v4l2-ctrls.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_core.h"
+
+#define DDR_TYPE_LPDDR4   0x6
+#define DDR_TYPE_LPDDR4X  0x7
+#define DDR_TYPE_LPDDR5   0x8
+#define DDR_TYPE_LPDDR5X  0x9
+
+#define UBWC_CONFIG(mc, ml, hbb, bs1, bs2, bs3, bsp) \
+{	                                                 \
+	.max_channels = mc,                              \
+	.mal_length = ml,                                \
+	.highest_bank_bit = hbb,                         \
+	.bank_swzl_level = bs1,                          \
+	.bank_swz2_level = bs2,                          \
+	.bank_swz3_level = bs3,                          \
+	.bank_spreading = bsp,                           \
+}
+
+struct bw_table {
+	const char      *name;
+	u32              min_kbps;
+	u32              max_kbps;
+};
+
+struct pd_table {
+	const char      *name;
+};
+
+struct regulator_table {
+	const char      *name;
+	bool             hw_trigger;
+};
+
+struct clk_table {
+	const char      *name;
+	u32              clk_id;
+	bool             scaling;
+};
+
+struct clk_rst_table {
+	const char      *name;
+	bool             exclusive_release;
+};
+
+struct subcache_table {
+	const char      *name;
+	u32              llcc_id;
+};
+
+struct context_bank_table {
+	const char      *name;
+	u32              start;
+	u32              size;
+	bool             secure;
+	bool             dma_coherant;
+	u32              region;
+	u64              dma_mask;
+};
+
+struct freq_table {
+	unsigned long    freq;
+};
+
+struct reg_preset_table {
+	u32              reg;
+	u32              value;
+	u32              mask;
+};
+
+struct msm_vidc_ubwc_config_data {
+	u32              max_channels;
+	u32              mal_length;
+	u32              highest_bank_bit;
+	u32              bank_swzl_level;
+	u32              bank_swz2_level;
+	u32              bank_swz3_level;
+	u32              bank_spreading;
+};
+
+struct codec_info {
+	u32 v4l2_codec;
+	enum msm_vidc_codec_type vidc_codec;
+	const char *pixfmt_name;
+};
+
+struct color_format_info {
+	u32 v4l2_color_format;
+	enum msm_vidc_colorformat_type vidc_color_format;
+	const char *pixfmt_name;
+};
+
+struct color_primaries_info {
+	u32 v4l2_color_primaries;
+	enum msm_vidc_color_primaries vidc_color_primaries;
+};
+
+struct transfer_char_info {
+	u32 v4l2_transfer_char;
+	enum msm_vidc_transfer_characteristics vidc_transfer_char;
+};
+
+struct matrix_coeff_info {
+	u32 v4l2_matrix_coeff;
+	enum msm_vidc_matrix_coefficients vidc_matrix_coeff;
+};
+
+struct msm_platform_core_capability {
+	enum msm_vidc_core_capability_type type;
+	u32 value;
+};
+
+struct msm_platform_inst_capability {
+	enum msm_vidc_inst_capability_type cap_id;
+	enum msm_vidc_domain_type domain;
+	enum msm_vidc_codec_type codec;
+	s32 min;
+	s32 max;
+	u32 step_or_mask;
+	s32 value;
+	u32 v4l2_id;
+	u32 hfi_id;
+	enum msm_vidc_inst_capability_flags flags;
+};
+
+struct msm_platform_inst_cap_dependency {
+	enum msm_vidc_inst_capability_type cap_id;
+	enum msm_vidc_domain_type domain;
+	enum msm_vidc_codec_type codec;
+	enum msm_vidc_inst_capability_type children[MAX_CAP_CHILDREN];
+	int (*adjust)(void *inst,
+		      struct v4l2_ctrl *ctrl);
+	int (*set)(void *inst,
+		   enum msm_vidc_inst_capability_type cap_id);
+};
+
+struct msm_vidc_compat_handle {
+	const char *compat;
+	int (*init_platform)(struct msm_vidc_core *core);
+	int (*init_iris)(struct msm_vidc_core *core);
+};
+
+struct msm_vidc_format_capability {
+	struct codec_info *codec_info;
+	u32 codec_info_size;
+	struct color_format_info *color_format_info;
+	u32 color_format_info_size;
+	struct color_primaries_info *color_prim_info;
+	u32 color_prim_info_size;
+	struct transfer_char_info *transfer_char_info;
+	u32 transfer_char_info_size;
+	struct matrix_coeff_info *matrix_coeff_info;
+	u32 matrix_coeff_info_size;
+};
+
+struct msm_vidc_platform_data {
+	const struct bw_table *bw_tbl;
+	unsigned int bw_tbl_size;
+	const struct regulator_table *regulator_tbl;
+	unsigned int regulator_tbl_size;
+	const struct pd_table *pd_tbl;
+	unsigned int pd_tbl_size;
+	const char * const *opp_tbl;
+	unsigned int opp_tbl_size;
+	const struct clk_table *clk_tbl;
+	unsigned int clk_tbl_size;
+	const struct clk_rst_table *clk_rst_tbl;
+	unsigned int clk_rst_tbl_size;
+	const struct subcache_table *subcache_tbl;
+	unsigned int subcache_tbl_size;
+	const struct context_bank_table *context_bank_tbl;
+	unsigned int context_bank_tbl_size;
+	struct freq_table *freq_tbl;
+	unsigned int freq_tbl_size;
+	const struct reg_preset_table *reg_prst_tbl;
+	unsigned int reg_prst_tbl_size;
+	struct msm_vidc_ubwc_config_data *ubwc_config;
+	const char *fwname;
+	u32 pas_id;
+	struct msm_platform_core_capability *core_data;
+	u32 core_data_size;
+	struct msm_platform_inst_capability *inst_cap_data;
+	u32 inst_cap_data_size;
+	struct msm_platform_inst_cap_dependency *inst_cap_dependency_data;
+	u32 inst_cap_dependency_data_size;
+	struct msm_vidc_format_capability *format_data;
+	const u32 *psc_avc_tbl;
+	unsigned int psc_avc_tbl_size;
+	const u32 *psc_hevc_tbl;
+	unsigned int psc_hevc_tbl_size;
+	const u32 *psc_vp9_tbl;
+	unsigned int psc_vp9_tbl_size;
+	const u32 *dec_input_prop_avc;
+	unsigned int dec_input_prop_size_avc;
+	const u32 *dec_input_prop_hevc;
+	unsigned int dec_input_prop_size_hevc;
+	const u32 *dec_input_prop_vp9;
+	unsigned int dec_input_prop_size_vp9;
+	const u32 *dec_output_prop_avc;
+	unsigned int dec_output_prop_size_avc;
+	const u32 *dec_output_prop_hevc;
+	unsigned int dec_output_prop_size_hevc;
+	const u32 *dec_output_prop_vp9;
+	unsigned int dec_output_prop_size_vp9;
+};
+
+struct msm_vidc_platform {
+	struct msm_vidc_platform_data data;
+};
+
+static inline bool is_sys_cache_present(struct msm_vidc_core *core)
+{
+	return !!core->platform->data.subcache_tbl_size;
+}
+
+int msm_vidc_init_platform(struct msm_vidc_core *core);
+
+/* control framework support functions */
+
+enum msm_vidc_inst_capability_type msm_vidc_get_cap_id(struct msm_vidc_inst *inst, u32 id);
+int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap,
+			      s32 adjusted_val, const char *func);
+bool is_parent_available(struct msm_vidc_inst *inst, u32 cap_id,
+			 u32 check_parent, const char *func);
+int msm_vidc_get_parent_value(struct msm_vidc_inst *inst, u32 cap, u32 parent,
+			      s32 *value, const char *func);
+u32 msm_vidc_get_port_info(struct msm_vidc_inst *inst,
+			   enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_v4l2_menu_to_hfi(struct msm_vidc_inst *inst,
+			      enum msm_vidc_inst_capability_type cap_id, u32 *value);
+int msm_vidc_v4l2_to_hfi_enum(struct msm_vidc_inst *inst,
+			      enum msm_vidc_inst_capability_type cap_id, u32 *value);
+int msm_vidc_packetize_control(struct msm_vidc_inst *inst,
+			       enum msm_vidc_inst_capability_type cap_id, u32 payload_type,
+			       void *hfi_val, u32 payload_size, const char *func);
+int msm_vidc_adjust_bitrate(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_layer_bitrate(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_bitrate_mode(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_entropy_mode(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_profile(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_ltr_count(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_use_ltr(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_mark_ltr(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_delta_based_rc(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_output_order(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_input_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_output_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_transform_8x8(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_chroma_qp_index_offset(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_slice_count(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_layer_count(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_gop_size(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_b_frame(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_peak_bitrate(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_hevc_min_qp(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_hevc_max_qp(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_hevc_i_frame_qp(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_hevc_p_frame_qp(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_hevc_b_frame_qp(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_bitrate_boost(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_min_quality(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_all_intra(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_dec_slice_mode(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_adjust_ir_period(void *instance, struct v4l2_ctrl *ctrl);
+int msm_vidc_set_header_mode(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_deblock_mode(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_min_qp(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_max_qp(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_frame_qp(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_req_sync_frame(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_chroma_qp_index_offset(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_slice_count(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_layer_count_and_type(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_gop_size(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_bitrate(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_layer_bitrate(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_u32(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_u32_packed(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_u32_enum(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_constant_quality(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_cbr_related_properties(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_use_and_mark_ltr(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_nal_length(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_flip(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_rotation(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_ir_period(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_stage(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_pipe(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_level(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_q16(void *instance, enum msm_vidc_inst_capability_type cap_id);
+int msm_vidc_set_vui_timing_info(void *instance, enum msm_vidc_inst_capability_type cap_id);
+
+#endif // _MSM_VIDC_PLATFORM_H_
diff --git a/drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c b/drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
new file mode 100644
index 0000000..d7441ea
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
@@ -0,0 +1,2499 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "hfi_packet.h"
+#include "hfi_property.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_iris3.h"
+#include "msm_vidc_sm8550.h"
+#include "msm_vidc_memory.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_v4l2.h"
+#include "msm_vidc_vb2.h"
+#include "venus_hfi.h"
+
+#define CAP_TO_8BIT_QP(a) {          \
+	if ((a) < MIN_QP_8BIT)                 \
+		(a) = MIN_QP_8BIT;             \
+}
+
+/*
+ * Below calculation for number of reference frames
+ * is picked up from hfi macro HFI_IRIS3_ENC_RECON_BUF_COUNT
+ */
+#define SLIDING_WINDOW_REF_FRAMES(codec, total_hp_layers, ltr_count, num_ref) {   \
+	if (codec == MSM_VIDC_HEVC) {                                          \
+		num_ref = (total_hp_layers + 1) >> 1;                          \
+	} else if (codec == MSM_VIDC_H264) {                                   \
+		if (total_hp_layers < 4)                                       \
+			num_ref = (total_hp_layers - 1);                       \
+		else                                                           \
+			num_ref = total_hp_layers;                             \
+	}                                                                      \
+	if (ltr_count)                                                         \
+		num_ref = num_ref + ltr_count;                                 \
+}
+
+static struct v4l2_file_operations msm_v4l2_file_operations = {
+	.owner                          = THIS_MODULE,
+	.open                           = msm_v4l2_open,
+	.release                        = msm_v4l2_close,
+	.unlocked_ioctl                 = video_ioctl2,
+	.poll                           = msm_v4l2_poll,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_enc = {
+	.vidioc_querycap                = msm_v4l2_querycap,
+	.vidioc_enum_fmt_vid_cap        = msm_v4l2_enum_fmt,
+	.vidioc_enum_fmt_vid_out        = msm_v4l2_enum_fmt,
+	.vidioc_enum_framesizes         = msm_v4l2_enum_framesizes,
+	.vidioc_enum_frameintervals     = msm_v4l2_enum_frameintervals,
+	.vidioc_try_fmt_vid_cap_mplane  = msm_v4l2_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane  = msm_v4l2_try_fmt,
+	.vidioc_s_fmt_vid_cap           = msm_v4l2_s_fmt,
+	.vidioc_s_fmt_vid_out           = msm_v4l2_s_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           = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out           = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_cap_mplane    = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane    = msm_v4l2_g_fmt,
+	.vidioc_g_selection             = msm_v4l2_g_selection,
+	.vidioc_s_selection             = msm_v4l2_s_selection,
+	.vidioc_s_parm                  = msm_v4l2_s_parm,
+	.vidioc_g_parm                  = msm_v4l2_g_parm,
+	.vidioc_reqbufs                 = msm_v4l2_reqbufs,
+	.vidioc_querybuf                = msm_v4l2_querybuf,
+	.vidioc_create_bufs             = msm_v4l2_create_bufs,
+	.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_queryctrl               = msm_v4l2_queryctrl,
+	.vidioc_querymenu               = msm_v4l2_querymenu,
+	.vidioc_subscribe_event         = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event       = msm_v4l2_unsubscribe_event,
+	.vidioc_try_encoder_cmd         = msm_v4l2_try_encoder_cmd,
+	.vidioc_encoder_cmd             = msm_v4l2_encoder_cmd,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_dec = {
+	.vidioc_querycap                = msm_v4l2_querycap,
+	.vidioc_enum_fmt_vid_cap        = msm_v4l2_enum_fmt,
+	.vidioc_enum_fmt_vid_out        = msm_v4l2_enum_fmt,
+	.vidioc_enum_framesizes         = msm_v4l2_enum_framesizes,
+	.vidioc_enum_frameintervals     = msm_v4l2_enum_frameintervals,
+	.vidioc_try_fmt_vid_cap_mplane  = msm_v4l2_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane  = msm_v4l2_try_fmt,
+	.vidioc_s_fmt_vid_cap           = msm_v4l2_s_fmt,
+	.vidioc_s_fmt_vid_out           = msm_v4l2_s_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           = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out           = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_cap_mplane    = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane    = msm_v4l2_g_fmt,
+	.vidioc_g_selection             = msm_v4l2_g_selection,
+	.vidioc_s_selection             = msm_v4l2_s_selection,
+	.vidioc_reqbufs                 = msm_v4l2_reqbufs,
+	.vidioc_querybuf                = msm_v4l2_querybuf,
+	.vidioc_create_bufs             = msm_v4l2_create_bufs,
+	.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_queryctrl               = msm_v4l2_queryctrl,
+	.vidioc_querymenu               = msm_v4l2_querymenu,
+	.vidioc_subscribe_event         = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event       = msm_v4l2_unsubscribe_event,
+	.vidioc_try_decoder_cmd         = msm_v4l2_try_decoder_cmd,
+	.vidioc_decoder_cmd             = msm_v4l2_decoder_cmd,
+};
+
+static const struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = {
+	.s_ctrl                         = msm_v4l2_op_s_ctrl,
+	.g_volatile_ctrl                = msm_v4l2_op_g_volatile_ctrl,
+};
+
+static const struct vb2_ops msm_vb2_ops = {
+	.queue_setup                    = msm_vb2_queue_setup,
+	.start_streaming                = msm_vb2_start_streaming,
+	.buf_queue                      = msm_vb2_buf_queue,
+	.stop_streaming                 = msm_vb2_stop_streaming,
+};
+
+static struct vb2_mem_ops msm_vb2_mem_ops = {
+	.alloc                          = msm_vb2_alloc,
+	.put                            = msm_vb2_put,
+	.mmap                           = msm_vb2_mmap,
+	.attach_dmabuf                  = msm_vb2_attach_dmabuf,
+	.detach_dmabuf                  = msm_vb2_detach_dmabuf,
+	.map_dmabuf                     = msm_vb2_map_dmabuf,
+	.unmap_dmabuf                   = msm_vb2_unmap_dmabuf,
+};
+
+static struct v4l2_m2m_ops msm_v4l2_m2m_ops = {
+	.device_run                     = msm_v4l2_m2m_device_run,
+	.job_abort                      = msm_v4l2_m2m_job_abort,
+};
+
+static const struct msm_vidc_compat_handle compat_handle[] = {
+	{
+		.compat                     = "qcom,sm8550-vidc",
+		.init_platform              = msm_vidc_init_platform_sm8550,
+		.init_iris                  = msm_vidc_init_iris3,
+	},
+};
+
+static int msm_vidc_init_ops(struct msm_vidc_core *core)
+{
+	d_vpr_h("%s: initialize ops\n", __func__);
+	core->v4l2_file_ops = &msm_v4l2_file_operations;
+	core->v4l2_ioctl_ops_enc = &msm_v4l2_ioctl_ops_enc;
+	core->v4l2_ioctl_ops_dec = &msm_v4l2_ioctl_ops_dec;
+	core->v4l2_ctrl_ops = &msm_v4l2_ctrl_ops;
+	core->vb2_ops = &msm_vb2_ops;
+	core->vb2_mem_ops = &msm_vb2_mem_ops;
+	core->v4l2_m2m_ops = &msm_v4l2_m2m_ops;
+	core->mem_ops = get_mem_ops();
+	if (!core->mem_ops) {
+		d_vpr_e("%s: invalid memory ops\n", __func__);
+		return -EINVAL;
+	}
+	core->res_ops = get_resources_ops();
+	if (!core->res_ops) {
+		d_vpr_e("%s: invalid resource ops\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_vidc_init_platform_variant(struct msm_vidc_core *core)
+{
+	struct device *dev = NULL;
+	int i, rc = 0;
+
+	dev = &core->pdev->dev;
+
+	/* select platform based on compatible match */
+	for (i = 0; i < ARRAY_SIZE(compat_handle); i++) {
+		if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) {
+			rc = compat_handle[i].init_platform(core);
+			if (rc) {
+				d_vpr_e("%s: (%s) init failed with %d\n",
+					__func__, compat_handle[i].compat, rc);
+				return rc;
+			}
+			break;
+		}
+	}
+
+	/* handle unknown compat type */
+	if (i == ARRAY_SIZE(compat_handle)) {
+		d_vpr_e("%s: Unsupported device: (%s)\n", __func__, dev_name(dev));
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_init_vpu(struct msm_vidc_core *core)
+{
+	struct device *dev = NULL;
+	int i, rc = 0;
+
+	dev = &core->pdev->dev;
+
+	/* select platform based on compatible match */
+	for (i = 0; i < ARRAY_SIZE(compat_handle); i++) {
+		if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) {
+			rc = compat_handle[i].init_iris(core);
+			if (rc) {
+				d_vpr_e("%s: (%s) init failed with %d\n",
+					__func__, compat_handle[i].compat, rc);
+				return rc;
+			}
+			break;
+		}
+	}
+
+	/* handle unknown compat type */
+	if (i == ARRAY_SIZE(compat_handle)) {
+		d_vpr_e("%s: Unsupported device: (%s)\n", __func__, dev_name(dev));
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int msm_vidc_init_platform(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct msm_vidc_platform *platform = NULL;
+
+	platform = devm_kzalloc(&core->pdev->dev, sizeof(struct msm_vidc_platform),
+				GFP_KERNEL);
+	if (!platform) {
+		d_vpr_e("%s: failed to alloc memory for platform\n", __func__);
+		return -ENOMEM;
+	}
+
+	core->platform = platform;
+
+	/* selected ops can be re-assigned in platform specific file */
+	rc = msm_vidc_init_ops(core);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_init_platform_variant(core);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_init_vpu(core);
+
+	return rc;
+}
+
+/****************** control framework utility functions **********************/
+
+enum msm_vidc_inst_capability_type msm_vidc_get_cap_id(struct msm_vidc_inst *inst, u32 id)
+{
+	enum msm_vidc_inst_capability_type i = INST_CAP_NONE + 1;
+
+	enum msm_vidc_inst_capability_type cap_id = INST_CAP_NONE;
+
+	do {
+		if (inst->capabilities[i].v4l2_id == id) {
+			cap_id = inst->capabilities[i].cap_id;
+			break;
+		}
+		i++;
+	} while (i < INST_CAP_MAX);
+
+	return cap_id;
+}
+
+int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap_id,
+			      s32 adjusted_val, const char *func)
+{
+	int prev_value = 0;
+
+	prev_value = inst->capabilities[cap_id].value;
+	inst->capabilities[cap_id].value = adjusted_val;
+
+	if (prev_value != inst->capabilities[cap_id].value) {
+		i_vpr_h(inst,
+			"%s: updated database: name: %s, value: %#x -> %#x\n",
+			func, cap_name(cap_id),
+			prev_value, inst->capabilities[cap_id].value);
+	}
+
+	return 0;
+}
+
+bool is_parent_available(struct msm_vidc_inst *inst,
+			 u32 cap_id, u32 check_parent, const char *func)
+{
+	int i = 0;
+	u32 cap_child;
+
+	if (!is_valid_cap_id(cap_id) || !is_valid_cap_id(check_parent))
+		return false;
+
+	while (i < MAX_CAP_CHILDREN &&
+	       inst->capabilities[check_parent].children[i]) {
+		cap_child = inst->capabilities[check_parent].children[i];
+		if (cap_child == cap_id)
+			return true;
+		i++;
+	}
+
+	i_vpr_e(inst,
+		"%s: missing parent %s for %s\n",
+		func, cap_name(check_parent), cap_name(cap_id));
+	return false;
+}
+
+int msm_vidc_get_parent_value(struct msm_vidc_inst *inst,
+			      u32 cap_id, u32 parent, s32 *value, const char *func)
+{
+	int rc = 0;
+
+	if (is_parent_available(inst, cap_id, parent, func)) {
+		switch (parent) {
+		case BITRATE_MODE:
+			*value = inst->hfi_rc_type;
+			break;
+		case LAYER_TYPE:
+			*value = inst->hfi_layer_type;
+			break;
+		default:
+			*value = inst->capabilities[parent].value;
+			break;
+		}
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+u32 msm_vidc_get_port_info(struct msm_vidc_inst *inst,
+			   enum msm_vidc_inst_capability_type cap_id)
+{
+	if (inst->capabilities[cap_id].flags & CAP_FLAG_INPUT_PORT &&
+	    inst->capabilities[cap_id].flags & CAP_FLAG_OUTPUT_PORT) {
+		if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+			return get_hfi_port(inst, INPUT_PORT);
+		else
+			return get_hfi_port(inst, OUTPUT_PORT);
+	}
+
+	if (inst->capabilities[cap_id].flags & CAP_FLAG_INPUT_PORT)
+		return get_hfi_port(inst, INPUT_PORT);
+	else if (inst->capabilities[cap_id].flags & CAP_FLAG_OUTPUT_PORT)
+		return get_hfi_port(inst, OUTPUT_PORT);
+	else
+		return HFI_PORT_NONE;
+}
+
+int msm_vidc_v4l2_menu_to_hfi(struct msm_vidc_inst *inst,
+			      enum msm_vidc_inst_capability_type cap_id, u32 *value)
+{
+	switch (cap_id) {
+	case ENTROPY_MODE:
+		switch (inst->capabilities[cap_id].value) {
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
+			*value = 1;
+			break;
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
+			*value = 0;
+			break;
+		default:
+			*value = 1;
+			goto set_default;
+		}
+		return 0;
+	default:
+		i_vpr_e(inst,
+			"%s: mapping not specified for ctrl_id: %#x\n",
+			__func__, inst->capabilities[cap_id].v4l2_id);
+		return -EINVAL;
+	}
+
+set_default:
+	i_vpr_e(inst,
+		"%s: invalid value %d for ctrl id: %#x. Set default: %u\n",
+		__func__, inst->capabilities[cap_id].value,
+		inst->capabilities[cap_id].v4l2_id, *value);
+	return 0;
+}
+
+int msm_vidc_v4l2_to_hfi_enum(struct msm_vidc_inst *inst,
+			      enum msm_vidc_inst_capability_type cap_id, u32 *value)
+{
+	switch (cap_id) {
+	case BITRATE_MODE:
+		*value = inst->hfi_rc_type;
+		return 0;
+	case PROFILE:
+	case LEVEL:
+	case HEVC_TIER:
+	case LAYER_TYPE:
+		if (inst->codec == MSM_VIDC_HEVC) {
+			switch (inst->capabilities[cap_id].value) {
+			case V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B:
+				*value = HFI_HIER_B;
+				break;
+			case V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P:
+				//TODO (AS): check if this is right mapping
+				*value = HFI_HIER_P_SLIDING_WINDOW;
+				break;
+			default:
+				*value = HFI_HIER_P_SLIDING_WINDOW;
+				goto set_default;
+			}
+		}
+		return 0;
+	case ROTATION:
+		switch (inst->capabilities[cap_id].value) {
+		case 0:
+			*value = HFI_ROTATION_NONE;
+			break;
+		case 90:
+			*value = HFI_ROTATION_90;
+			break;
+		case 180:
+			*value = HFI_ROTATION_180;
+			break;
+		case 270:
+			*value = HFI_ROTATION_270;
+			break;
+		default:
+			*value = HFI_ROTATION_NONE;
+			goto set_default;
+		}
+		return 0;
+	case LF_MODE:
+		if (inst->codec == MSM_VIDC_HEVC) {
+			switch (inst->capabilities[cap_id].value) {
+			case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
+				*value = HFI_DEBLOCK_ALL_BOUNDARY;
+				break;
+			case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
+				*value = HFI_DEBLOCK_DISABLE;
+				break;
+			case DB_HEVC_DISABLE_SLICE_BOUNDARY:
+				*value = HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY;
+				break;
+			default:
+				*value = HFI_DEBLOCK_ALL_BOUNDARY;
+				goto set_default;
+			}
+		} else if (inst->codec == MSM_VIDC_H264) {
+			switch (inst->capabilities[cap_id].value) {
+			case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+				*value = HFI_DEBLOCK_ALL_BOUNDARY;
+				break;
+			case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+				*value = HFI_DEBLOCK_DISABLE;
+				break;
+			case DB_H264_DISABLE_SLICE_BOUNDARY:
+				*value = HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY;
+				break;
+			default:
+				*value = HFI_DEBLOCK_ALL_BOUNDARY;
+				goto set_default;
+			}
+		}
+		return 0;
+	case NAL_LENGTH_FIELD:
+		switch (inst->capabilities[cap_id].value) {
+		case V4L2_MPEG_VIDEO_HEVC_SIZE_4:
+			*value = HFI_NAL_LENGTH_SIZE_4;
+			break;
+		default:
+			*value = HFI_NAL_LENGTH_STARTCODES;
+			goto set_default;
+		}
+		return 0;
+	default:
+		i_vpr_e(inst,
+			"%s: mapping not specified for ctrl_id: %#x\n",
+			__func__, inst->capabilities[cap_id].v4l2_id);
+		return -EINVAL;
+	}
+
+set_default:
+	i_vpr_e(inst,
+		"%s: invalid value %d for ctrl id: %#x. Set default: %u\n",
+		__func__, inst->capabilities[cap_id].value,
+		inst->capabilities[cap_id].v4l2_id, *value);
+	return 0;
+}
+
+int msm_vidc_packetize_control(struct msm_vidc_inst *inst,
+			       enum msm_vidc_inst_capability_type cap_id, u32 payload_type,
+			       void *hfi_val, u32 payload_size, const char *func)
+{
+	int rc = 0;
+	u64 payload = 0;
+
+	if (payload_size > sizeof(u32)) {
+		i_vpr_e(inst, "%s: payload size is more than u32 for cap[%d] %s\n",
+			func, cap_id, cap_name(cap_id));
+		return -EINVAL;
+	}
+
+	if (payload_size == sizeof(u32))
+		payload = *(u32 *)hfi_val;
+	else if (payload_size == sizeof(u8))
+		payload = *(u8 *)hfi_val;
+	else if (payload_size == sizeof(u16))
+		payload = *(u16 *)hfi_val;
+
+	i_vpr_h(inst, FMT_STRING_SET_CAP,
+		cap_name(cap_id), inst->capabilities[cap_id].value, payload);
+
+	rc = venus_hfi_session_property(inst,
+					inst->capabilities[cap_id].hfi_id,
+					HFI_HOST_FLAGS_NONE,
+					msm_vidc_get_port_info(inst, cap_id),
+					payload_type,
+					hfi_val,
+					payload_size);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to set cap[%d] %s to fw\n",
+			func, cap_id, cap_name(cap_id));
+		return rc;
+	}
+
+	return 0;
+}
+
+/*************** End of control framework utility functions ******************/
+
+/*********************** Control Adjust functions ****************************/
+
+int msm_vidc_adjust_entropy_mode(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 profile = -1;
+
+	/* ctrl is always NULL in streamon case */
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[ENTROPY_MODE].value;
+
+	if (inst->codec != MSM_VIDC_H264) {
+		i_vpr_e(inst,
+			"%s: incorrect entry in database. fix the database\n",
+			__func__);
+		return 0;
+	}
+
+	if (msm_vidc_get_parent_value(inst, ENTROPY_MODE, PROFILE, &profile, __func__))
+		return -EINVAL;
+
+	if (profile == V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ||
+	    profile == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE)
+		adjusted_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC;
+
+	msm_vidc_update_cap_value(inst, ENTROPY_MODE, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_bitrate_mode(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	int lossless, frame_rc, bitrate_mode, frame_skip;
+	u32 hfi_value = 0;
+
+	bitrate_mode = inst->capabilities[BITRATE_MODE].value;
+	lossless = inst->capabilities[LOSSLESS].value;
+	frame_rc = inst->capabilities[FRAME_RC_ENABLE].value;
+	frame_skip = inst->capabilities[FRAME_SKIP_MODE].value;
+
+	if (lossless) {
+		hfi_value = HFI_RC_LOSSLESS;
+		goto update;
+	}
+
+	if (!frame_rc) {
+		hfi_value = HFI_RC_OFF;
+		goto update;
+	}
+
+	if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+		hfi_value = HFI_RC_VBR_CFR;
+	} else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) {
+		if (frame_skip)
+			hfi_value = HFI_RC_CBR_VFR;
+		else
+			hfi_value = HFI_RC_CBR_CFR;
+	} else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) {
+		hfi_value = HFI_RC_CQ;
+	}
+
+update:
+	inst->hfi_rc_type = hfi_value;
+	i_vpr_h(inst, "%s: hfi rc type: %#x\n",
+		__func__, inst->hfi_rc_type);
+
+	return 0;
+}
+
+int msm_vidc_adjust_profile(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 pix_fmt = -1;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[PROFILE].value;
+
+	/* PIX_FMTS dependency is common across all chipsets.
+	 * Hence, PIX_FMTS must be specified as Parent for HEVC profile.
+	 * Otherwise it would be a database error that should be fixed.
+	 */
+	if (msm_vidc_get_parent_value(inst, PROFILE, PIX_FMTS, &pix_fmt, __func__))
+		return -EINVAL;
+
+	/* 10 bit profile for 10 bit color format */
+	if (pix_fmt == MSM_VIDC_FMT_TP10C || pix_fmt == MSM_VIDC_FMT_P010)
+		adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
+	else
+		/* 8 bit profile for 8 bit color format */
+		adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
+
+	msm_vidc_update_cap_value(inst, PROFILE, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_ltr_count(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 rc_type = -1, all_intra = 0, pix_fmts = MSM_VIDC_FMT_NONE;
+	s32 layer_type = -1, enh_layer_count = -1;
+	u32 num_ref_frames = 0, max_exceeding_ref_frames = 0;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[LTR_COUNT].value;
+
+	if (msm_vidc_get_parent_value(inst, LTR_COUNT, BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if ((rc_type != HFI_RC_OFF &&
+	     rc_type != HFI_RC_CBR_CFR &&
+	     rc_type != HFI_RC_CBR_VFR)) {
+		adjusted_value = 0;
+		i_vpr_h(inst,
+			"%s: ltr count unsupported, rc_type: %#x\n",
+			__func__, rc_type);
+		goto exit;
+	}
+
+	if (is_valid_cap(inst, ALL_INTRA)) {
+		if (msm_vidc_get_parent_value(inst, LTR_COUNT, ALL_INTRA, &all_intra, __func__))
+			return -EINVAL;
+		if (all_intra) {
+			adjusted_value = 0;
+			goto exit;
+		}
+	}
+
+	if (!msm_vidc_get_parent_value(inst, LTR_COUNT, PIX_FMTS, &pix_fmts, __func__)) {
+		if (is_10bit_colorformat(pix_fmts))
+			adjusted_value = 0;
+	}
+
+	if (!msm_vidc_get_parent_value(inst, LTR_COUNT, ENH_LAYER_COUNT,
+				       &enh_layer_count, __func__) &&
+	    !msm_vidc_get_parent_value(inst, LTR_COUNT, LAYER_TYPE,
+				       &layer_type, __func__)) {
+		if (layer_type == HFI_HIER_P_SLIDING_WINDOW) {
+			SLIDING_WINDOW_REF_FRAMES(inst->codec,
+						  inst->capabilities[ENH_LAYER_COUNT].value + 1,
+						  adjusted_value, num_ref_frames);
+			if (num_ref_frames > MAX_ENCODING_REFERNCE_FRAMES) {
+				/*
+				 * reduce ltr count to avoid num ref
+				 * frames going beyond limit
+				 */
+				max_exceeding_ref_frames = num_ref_frames -
+					MAX_ENCODING_REFERNCE_FRAMES;
+				if (adjusted_value >= max_exceeding_ref_frames)
+					adjusted_value -= max_exceeding_ref_frames;
+				else
+					adjusted_value = 0;
+			}
+		}
+		i_vpr_h(inst,
+			"%s: ltr count %d enh_layers %d layer_type %d\n",
+			__func__, adjusted_value,
+			inst->capabilities[ENH_LAYER_COUNT].value,
+			layer_type);
+	}
+
+exit:
+	msm_vidc_update_cap_value(inst, LTR_COUNT,  adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_use_ltr(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value, ltr_count;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[USE_LTR].value;
+
+	/*
+	 * Since USE_LTR is only set dynamically, and LTR_COUNT is static
+	 * control, no need to make LTR_COUNT as parent for USE_LTR as
+	 * LTR_COUNT value will always be updated when dynamically USE_LTR
+	 * is set
+	 */
+	ltr_count = inst->capabilities[LTR_COUNT].value;
+	if (!ltr_count)
+		return 0;
+
+	if (adjusted_value <= 0 ||
+	    adjusted_value > ((1 << ltr_count) - 1)) {
+		/*
+		 * USE_LTR is bitmask value, hence should be
+		 * > 0 and <= (2 ^ LTR_COUNT) - 1
+		 */
+		i_vpr_e(inst, "%s: invalid value %d\n",
+			__func__, adjusted_value);
+		return 0;
+	}
+
+	/* USE_LTR value is a bitmask value */
+	msm_vidc_update_cap_value(inst, USE_LTR, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_mark_ltr(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value, ltr_count;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[MARK_LTR].value;
+
+	/*
+	 * Since MARK_LTR is only set dynamically, and LTR_COUNT is static
+	 * control, no need to make LTR_COUNT as parent for MARK_LTR as
+	 * LTR_COUNT value will always be updated when dynamically MARK_LTR
+	 * is set
+	 */
+	ltr_count = inst->capabilities[LTR_COUNT].value;
+	if (!ltr_count)
+		return 0;
+
+	if (adjusted_value < 0 ||
+	    adjusted_value > (ltr_count - 1)) {
+		/* MARK_LTR value should be >= 0 and <= (LTR_COUNT - 1) */
+		i_vpr_e(inst, "%s: invalid value %d\n",
+			__func__, adjusted_value);
+		return 0;
+	}
+
+	msm_vidc_update_cap_value(inst, MARK_LTR, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_delta_based_rc(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 rc_type = -1;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[TIME_DELTA_BASED_RC].value;
+
+	if (msm_vidc_get_parent_value(inst, TIME_DELTA_BASED_RC, BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if (rc_type == HFI_RC_OFF || rc_type == HFI_RC_CQ)
+		adjusted_value = 0;
+
+	msm_vidc_update_cap_value(inst, TIME_DELTA_BASED_RC, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_output_order(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	s32 display_delay = -1, display_delay_enable = -1;
+	u32 adjusted_value;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[OUTPUT_ORDER].value;
+
+	if (msm_vidc_get_parent_value(inst, OUTPUT_ORDER, DISPLAY_DELAY,
+				      &display_delay, __func__) ||
+		msm_vidc_get_parent_value(inst, OUTPUT_ORDER, DISPLAY_DELAY_ENABLE,
+					  &display_delay_enable, __func__))
+		return -EINVAL;
+
+	if (display_delay_enable && !display_delay)
+		adjusted_value = 1;
+
+	msm_vidc_update_cap_value(inst, OUTPUT_ORDER, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_input_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	u32 adjusted_value;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[INPUT_BUF_HOST_MAX_COUNT].value;
+
+	msm_vidc_update_cap_value(inst, INPUT_BUF_HOST_MAX_COUNT,
+				  adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_output_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	u32 adjusted_value;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[OUTPUT_BUF_HOST_MAX_COUNT].value;
+
+	msm_vidc_update_cap_value(inst, OUTPUT_BUF_HOST_MAX_COUNT,
+				  adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_transform_8x8(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 profile = -1;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[TRANSFORM_8X8].value;
+
+	if (inst->codec != MSM_VIDC_H264) {
+		i_vpr_e(inst,
+			"%s: incorrect entry in database. fix the database\n",
+			__func__);
+		return 0;
+	}
+
+	if (msm_vidc_get_parent_value(inst, TRANSFORM_8X8, PROFILE, &profile, __func__))
+		return -EINVAL;
+
+	if (profile != V4L2_MPEG_VIDEO_H264_PROFILE_HIGH &&
+	    profile != V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH)
+		adjusted_value = 0;
+
+	msm_vidc_update_cap_value(inst, TRANSFORM_8X8, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_chroma_qp_index_offset(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[CHROMA_QP_INDEX_OFFSET].value;
+
+	if (adjusted_value != MIN_CHROMA_QP_OFFSET)
+		adjusted_value = MAX_CHROMA_QP_OFFSET;
+
+	msm_vidc_update_cap_value(inst, CHROMA_QP_INDEX_OFFSET,
+				  adjusted_value, __func__);
+
+	return 0;
+}
+
+static bool msm_vidc_check_all_layer_bitrate_set(struct msm_vidc_inst *inst)
+{
+	bool layer_bitrate_set = true;
+	u32 cap_id = 0, i, enh_layer_count;
+	u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR};
+
+	enh_layer_count = inst->capabilities[ENH_LAYER_COUNT].value;
+
+	for (i = 0; i <= enh_layer_count; i++) {
+		if (i >= ARRAY_SIZE(layer_br_caps))
+			break;
+		cap_id = layer_br_caps[i];
+		if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)) {
+			layer_bitrate_set = false;
+			break;
+		}
+	}
+
+	return layer_bitrate_set;
+}
+
+static u32 msm_vidc_get_cumulative_bitrate(struct msm_vidc_inst *inst)
+{
+	int i;
+	u32 cap_id = 0;
+	u32 cumulative_br = 0;
+	s32 enh_layer_count;
+	u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR};
+
+	enh_layer_count = inst->capabilities[ENH_LAYER_COUNT].value;
+
+	for (i = 0; i <= enh_layer_count; i++) {
+		if (i >= ARRAY_SIZE(layer_br_caps))
+			break;
+		cap_id = layer_br_caps[i];
+		cumulative_br += inst->capabilities[cap_id].value;
+	}
+
+	return cumulative_br;
+}
+
+int msm_vidc_adjust_slice_count(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	struct v4l2_format *output_fmt;
+	s32 adjusted_value, rc_type = -1, slice_mode, all_intra = 0,
+		enh_layer_count = 0;
+	u32 slice_val, mbpf = 0, mbps = 0, max_mbpf = 0, max_mbps = 0, bitrate = 0;
+	u32 update_cap, max_avg_slicesize, output_width, output_height;
+	u32 min_width, min_height, max_width, max_height, fps;
+
+	slice_mode = ctrl ? ctrl->val :
+		inst->capabilities[SLICE_MODE].value;
+
+	if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE)
+		return 0;
+
+	bitrate = inst->capabilities[BIT_RATE].value;
+
+	if (msm_vidc_get_parent_value(inst, SLICE_MODE,
+				      BITRATE_MODE, &rc_type, __func__) ||
+		msm_vidc_get_parent_value(inst, SLICE_MODE,
+					  ENH_LAYER_COUNT, &enh_layer_count, __func__))
+		return -EINVAL;
+
+	if (enh_layer_count && msm_vidc_check_all_layer_bitrate_set(inst))
+		bitrate = msm_vidc_get_cumulative_bitrate(inst);
+
+	fps = inst->capabilities[FRAME_RATE].value >> 16;
+	if (fps > MAX_SLICES_FRAME_RATE ||
+	    (rc_type != HFI_RC_OFF &&
+	     rc_type != HFI_RC_CBR_CFR &&
+	     rc_type != HFI_RC_CBR_VFR &&
+	     rc_type != HFI_RC_VBR_CFR)) {
+		adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+		update_cap = SLICE_MODE;
+		i_vpr_h(inst,
+			"%s: slice unsupported, fps: %u, rc_type: %#x\n",
+			__func__, fps, rc_type);
+		goto exit;
+	}
+
+	if (is_valid_cap(inst, ALL_INTRA)) {
+		if (msm_vidc_get_parent_value(inst, SLICE_MODE,
+					      ALL_INTRA, &all_intra, __func__))
+			return -EINVAL;
+
+		if (all_intra == 1) {
+			adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+			update_cap = SLICE_MODE;
+			i_vpr_h(inst,
+				"%s: slice unsupported, all_intra %d\n", __func__, all_intra);
+			goto exit;
+		}
+	}
+
+	output_fmt = &inst->fmts[OUTPUT_PORT];
+	output_width = output_fmt->fmt.pix_mp.width;
+	output_height = output_fmt->fmt.pix_mp.height;
+
+	max_width = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+		MAX_MB_SLICE_WIDTH : MAX_BYTES_SLICE_WIDTH;
+	max_height = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+		MAX_MB_SLICE_HEIGHT : MAX_BYTES_SLICE_HEIGHT;
+	min_width = (inst->codec == MSM_VIDC_HEVC) ?
+		MIN_HEVC_SLICE_WIDTH : MIN_AVC_SLICE_WIDTH;
+	min_height = MIN_SLICE_HEIGHT;
+
+	/*
+	 * For V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB:
+	 * - width >= 384 and height >= 128
+	 * - width and height <= 4096
+	 * For V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES:
+	 * - width >= 192 and height >= 128
+	 * - width and height <= 1920
+	 */
+	if (output_width < min_width || output_height < min_height ||
+	    output_width > max_width || output_height > max_width) {
+		adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+		update_cap = SLICE_MODE;
+		i_vpr_h(inst,
+			"%s: slice unsupported, codec: %#x wxh: [%dx%d]\n",
+			__func__, inst->codec, output_width, output_height);
+		goto exit;
+	}
+
+	mbpf = NUM_MBS_PER_FRAME(output_height, output_width);
+	mbps = NUM_MBS_PER_SEC(output_height, output_width, fps);
+	max_mbpf = NUM_MBS_PER_FRAME(max_height, max_width);
+	max_mbps = NUM_MBS_PER_SEC(max_height, max_width, MAX_SLICES_FRAME_RATE);
+
+	if (mbpf > max_mbpf || mbps > max_mbps) {
+		adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+		update_cap = SLICE_MODE;
+		i_vpr_h(inst,
+			"%s: Unsupported, mbpf[%u] > max[%u], mbps[%u] > max[%u]\n",
+			__func__, mbpf, max_mbpf, mbps, max_mbps);
+		goto exit;
+	}
+
+	if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
+		update_cap = SLICE_MAX_MB;
+		slice_val = inst->capabilities[SLICE_MAX_MB].value;
+		slice_val = max(slice_val, mbpf / MAX_SLICES_PER_FRAME);
+	} else {
+		slice_val = inst->capabilities[SLICE_MAX_BYTES].value;
+		update_cap = SLICE_MAX_BYTES;
+		if (rc_type != HFI_RC_OFF) {
+			max_avg_slicesize = ((bitrate / fps) / 8) /
+				MAX_SLICES_PER_FRAME;
+			slice_val = max(slice_val, max_avg_slicesize);
+		}
+	}
+	adjusted_value = slice_val;
+
+exit:
+	msm_vidc_update_cap_value(inst, update_cap, adjusted_value, __func__);
+
+	return 0;
+}
+
+static int msm_vidc_adjust_static_layer_count_and_type(struct msm_vidc_inst *inst,
+						       s32 layer_count)
+{
+	bool hb_requested = false;
+
+	if (!layer_count) {
+		i_vpr_h(inst, "client not enabled layer encoding\n");
+		goto exit;
+	}
+
+	if (inst->hfi_rc_type == HFI_RC_CQ) {
+		i_vpr_h(inst, "rc type is CQ, disabling layer encoding\n");
+		layer_count = 0;
+		goto exit;
+	}
+
+	if (inst->codec == MSM_VIDC_H264) {
+		if (!inst->capabilities[LAYER_ENABLE].value) {
+			layer_count = 0;
+			goto exit;
+		}
+
+		hb_requested = (inst->capabilities[LAYER_TYPE].value ==
+				V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) ?
+				true : false;
+	} else if (inst->codec == MSM_VIDC_HEVC) {
+		hb_requested = (inst->capabilities[LAYER_TYPE].value ==
+				V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) ?
+				true : false;
+	}
+
+	if (hb_requested && inst->hfi_rc_type != HFI_RC_VBR_CFR) {
+		i_vpr_h(inst,
+			"%s: HB layer encoding is supported for VBR rc only\n",
+			__func__);
+		layer_count = 0;
+		goto exit;
+	}
+
+	/* decide hfi layer type */
+	if (hb_requested) {
+		inst->hfi_layer_type = HFI_HIER_B;
+	} else {
+		/* HP requested */
+		inst->hfi_layer_type = HFI_HIER_P_SLIDING_WINDOW;
+		if (inst->codec == MSM_VIDC_H264 &&
+		    inst->hfi_rc_type == HFI_RC_VBR_CFR)
+			inst->hfi_layer_type = HFI_HIER_P_HYBRID_LTR;
+	}
+
+	/* sanitize layer count based on layer type and codec, and rc type */
+	if (inst->hfi_layer_type == HFI_HIER_B) {
+		if (layer_count > MAX_ENH_LAYER_HB)
+			layer_count = MAX_ENH_LAYER_HB;
+	} else if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR) {
+		if (layer_count > MAX_AVC_ENH_LAYER_HYBRID_HP)
+			layer_count = MAX_AVC_ENH_LAYER_HYBRID_HP;
+	} else if (inst->hfi_layer_type == HFI_HIER_P_SLIDING_WINDOW) {
+		if (inst->codec == MSM_VIDC_H264) {
+			if (layer_count > MAX_AVC_ENH_LAYER_SLIDING_WINDOW)
+				layer_count = MAX_AVC_ENH_LAYER_SLIDING_WINDOW;
+		} else if (inst->codec == MSM_VIDC_HEVC) {
+			if (inst->hfi_rc_type == HFI_RC_VBR_CFR) {
+				if (layer_count > MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW)
+					layer_count = MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW;
+			} else {
+				if (layer_count > MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW)
+					layer_count = MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW;
+			}
+		}
+	}
+
+exit:
+	msm_vidc_update_cap_value(inst, ENH_LAYER_COUNT, layer_count, __func__);
+	inst->capabilities[ENH_LAYER_COUNT].max = layer_count;
+	return 0;
+}
+
+int msm_vidc_adjust_layer_count(void *instance, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	s32 client_layer_count;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	client_layer_count = ctrl ? ctrl->val :
+		inst->capabilities[ENH_LAYER_COUNT].value;
+
+	if (!is_parent_available(inst, ENH_LAYER_COUNT, BITRATE_MODE, __func__))
+		return -EINVAL;
+
+	if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		rc = msm_vidc_adjust_static_layer_count_and_type(inst, client_layer_count);
+		if (rc)
+			goto exit;
+	} else {
+		if (inst->hfi_rc_type == HFI_RC_CBR_CFR ||
+		    inst->hfi_rc_type == HFI_RC_CBR_VFR) {
+			i_vpr_h(inst,
+				"%s: ignoring dynamic layer count change for CBR mode\n",
+				__func__);
+			goto exit;
+		}
+
+		if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR ||
+		    inst->hfi_layer_type == HFI_HIER_P_SLIDING_WINDOW) {
+			/* dynamic layer count change is only supported for HP */
+			if (client_layer_count >
+			    inst->capabilities[ENH_LAYER_COUNT].max)
+				client_layer_count =
+					inst->capabilities[ENH_LAYER_COUNT].max;
+
+			msm_vidc_update_cap_value(inst, ENH_LAYER_COUNT,
+						  client_layer_count, __func__);
+		}
+	}
+
+exit:
+	return rc;
+}
+
+int msm_vidc_adjust_gop_size(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 adjusted_value, enh_layer_count = -1;
+	u32 min_gop_size, num_subgops;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[GOP_SIZE].value;
+
+	if (msm_vidc_get_parent_value(inst, GOP_SIZE,
+				      ENH_LAYER_COUNT, &enh_layer_count, __func__))
+		return -EINVAL;
+
+	if (!enh_layer_count)
+		goto exit;
+
+	/*
+	 * Layer encoding needs GOP size to be multiple of subgop size
+	 * And subgop size is 2 ^ number of enhancement layers.
+	 */
+
+	/* v4l2 layer count is the number of enhancement layers */
+	min_gop_size = 1 << enh_layer_count;
+	num_subgops = (adjusted_value + (min_gop_size >> 1)) /
+			min_gop_size;
+	if (num_subgops)
+		adjusted_value = num_subgops * min_gop_size;
+	else
+		adjusted_value = min_gop_size;
+
+exit:
+	msm_vidc_update_cap_value(inst, GOP_SIZE, adjusted_value, __func__);
+	return 0;
+}
+
+int msm_vidc_adjust_b_frame(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 adjusted_value, enh_layer_count = -1;
+	const u32 max_bframe_size = 7;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[B_FRAME].value;
+
+	if (msm_vidc_get_parent_value(inst, B_FRAME,
+				      ENH_LAYER_COUNT, &enh_layer_count, __func__))
+		return -EINVAL;
+
+	if (!enh_layer_count || inst->hfi_layer_type != HFI_HIER_B) {
+		adjusted_value = 0;
+		goto exit;
+	}
+
+	adjusted_value = (1 << enh_layer_count) - 1;
+	/* Allowed Bframe values are 0, 1, 3, 7 */
+	if (adjusted_value > max_bframe_size)
+		adjusted_value = max_bframe_size;
+
+exit:
+	msm_vidc_update_cap_value(inst, B_FRAME, adjusted_value, __func__);
+	return 0;
+}
+
+int msm_vidc_adjust_bitrate(void *instance, struct v4l2_ctrl *ctrl)
+{
+	int i, rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	s32 adjusted_value, enh_layer_count;
+	u32 cumulative_bitrate = 0, cap_id = 0, cap_value = 0;
+	u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR};
+	u32 max_bitrate = 0;
+
+	/* ignore layer bitrate when total bitrate is set */
+	if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) {
+		/*
+		 * For static case, ctrl is null.
+		 * For dynamic case, only BIT_RATE cap uses this adjust function.
+		 * Hence, no need to check for ctrl id to be BIT_RATE control, and not
+		 * any of layer bitrate controls.
+		 */
+		adjusted_value = ctrl ? ctrl->val : inst->capabilities[BIT_RATE].value;
+		msm_vidc_update_cap_value(inst, BIT_RATE, adjusted_value, __func__);
+
+		return 0;
+	}
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	if (msm_vidc_get_parent_value(inst, BIT_RATE,
+				      ENH_LAYER_COUNT, &enh_layer_count, __func__))
+		return -EINVAL;
+
+	/* get max bit rate for current session config*/
+	max_bitrate = msm_vidc_get_max_bitrate(inst);
+	if (inst->capabilities[BIT_RATE].value > max_bitrate)
+		msm_vidc_update_cap_value(inst, BIT_RATE, max_bitrate, __func__);
+
+	/*
+	 * ENH_LAYER_COUNT cap max is positive only if
+	 * layer encoding is enabled during streamon.
+	 */
+	if (inst->capabilities[ENH_LAYER_COUNT].max) {
+		if (!msm_vidc_check_all_layer_bitrate_set(inst)) {
+			i_vpr_h(inst,
+				"%s: client did not set all layer bitrates\n",
+				__func__);
+			return 0;
+		}
+
+		cumulative_bitrate = msm_vidc_get_cumulative_bitrate(inst);
+
+		/* cap layer bitrates to max supported bitrate */
+		if (cumulative_bitrate > max_bitrate) {
+			u32 decrement_in_value = 0;
+			u32 decrement_in_percent = ((cumulative_bitrate - max_bitrate) * 100) /
+				max_bitrate;
+
+			cumulative_bitrate = 0;
+			for (i = 0; i <= enh_layer_count; i++) {
+				if (i >= ARRAY_SIZE(layer_br_caps))
+					break;
+				cap_id = layer_br_caps[i];
+				cap_value = inst->capabilities[cap_id].value;
+
+				decrement_in_value = (cap_value *
+					decrement_in_percent) / 100;
+				cumulative_bitrate += (cap_value - decrement_in_value);
+
+				/*
+				 * cap value for the L*_BR is changed. Hence, update cap,
+				 * and add to FW_LIST to set new values to firmware.
+				 */
+				msm_vidc_update_cap_value(inst, cap_id,
+							  (cap_value - decrement_in_value),
+							   __func__);
+			}
+		}
+
+		i_vpr_h(inst,
+			"%s: update BIT_RATE with cumulative bitrate\n",
+			__func__);
+		msm_vidc_update_cap_value(inst, BIT_RATE,
+					  cumulative_bitrate, __func__);
+	}
+
+	return rc;
+}
+
+int msm_vidc_adjust_layer_bitrate(void *instance, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	u32 cumulative_bitrate = 0;
+	u32 client_set_cap_id = INST_CAP_NONE;
+	u32 old_br = 0, new_br = 0, exceeded_br = 0;
+	s32 max_bitrate;
+
+	if (!ctrl)
+		return 0;
+
+	/* ignore layer bitrate when total bitrate is set */
+	if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET)
+		return 0;
+
+	/*
+	 * This is no-op function because layer bitrates were already adjusted
+	 * in msm_vidc_adjust_bitrate function
+	 */
+	if (!inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	/*
+	 * ENH_LAYER_COUNT cap max is positive only if
+	 * layer encoding is enabled during streamon.
+	 */
+	if (!inst->capabilities[ENH_LAYER_COUNT].max) {
+		i_vpr_e(inst, "%s: layers not enabled\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!msm_vidc_check_all_layer_bitrate_set(inst)) {
+		i_vpr_h(inst,
+			"%s: client did not set all layer bitrates\n",
+			__func__);
+		return 0;
+	}
+
+	client_set_cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+	if (client_set_cap_id == INST_CAP_NONE) {
+		i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n",
+			__func__, ctrl->name);
+		return -EINVAL;
+	}
+
+	cumulative_bitrate = msm_vidc_get_cumulative_bitrate(inst);
+	max_bitrate = inst->capabilities[BIT_RATE].max;
+	old_br = inst->capabilities[client_set_cap_id].value;
+	new_br = ctrl->val;
+
+	/*
+	 * new bitrate is not supposed to cause cumulative bitrate to
+	 * exceed max supported bitrate
+	 */
+
+	if ((cumulative_bitrate - old_br + new_br) > max_bitrate) {
+		/* adjust new bitrate */
+		exceeded_br = (cumulative_bitrate - old_br + new_br) - max_bitrate;
+		new_br = ctrl->val - exceeded_br;
+	}
+	msm_vidc_update_cap_value(inst, client_set_cap_id, new_br, __func__);
+
+	/* adjust totol bitrate cap */
+	i_vpr_h(inst,
+		"%s: update BIT_RATE with cumulative bitrate\n",
+		__func__);
+	msm_vidc_update_cap_value(inst, BIT_RATE,
+				  msm_vidc_get_cumulative_bitrate(inst), __func__);
+
+	return rc;
+}
+
+int msm_vidc_adjust_peak_bitrate(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 rc_type = -1, bitrate = -1;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[PEAK_BITRATE].value;
+
+	if (msm_vidc_get_parent_value(inst, PEAK_BITRATE,
+				      BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if (rc_type != HFI_RC_CBR_CFR &&
+	    rc_type != HFI_RC_CBR_VFR)
+		return 0;
+
+	if (msm_vidc_get_parent_value(inst, PEAK_BITRATE,
+				      BIT_RATE, &bitrate, __func__))
+		return -EINVAL;
+
+	/* Peak Bitrate should be larger than or equal to avg bitrate */
+	if (inst->capabilities[PEAK_BITRATE].flags & CAP_FLAG_CLIENT_SET) {
+		if (adjusted_value < bitrate)
+			adjusted_value = bitrate;
+	} else {
+		adjusted_value = inst->capabilities[BIT_RATE].value;
+	}
+
+	msm_vidc_update_cap_value(inst, PEAK_BITRATE, adjusted_value, __func__);
+
+	return 0;
+}
+
+static int msm_vidc_adjust_hevc_qp(struct msm_vidc_inst *inst,
+				   enum msm_vidc_inst_capability_type cap_id)
+{
+	s32 pix_fmt = -1;
+
+	if (!(inst->codec == MSM_VIDC_HEVC)) {
+		i_vpr_e(inst,
+			"%s: incorrect cap[%d] %s entry in database, fix database\n",
+			__func__, cap_id, cap_name(cap_id));
+		return -EINVAL;
+	}
+
+	if (msm_vidc_get_parent_value(inst, cap_id, PIX_FMTS, &pix_fmt, __func__))
+		return -EINVAL;
+
+	if (pix_fmt == MSM_VIDC_FMT_P010 || pix_fmt == MSM_VIDC_FMT_TP10C)
+		goto exit;
+
+	CAP_TO_8BIT_QP(inst->capabilities[cap_id].value);
+	if (cap_id == MIN_FRAME_QP) {
+		CAP_TO_8BIT_QP(inst->capabilities[I_FRAME_MIN_QP].value);
+		CAP_TO_8BIT_QP(inst->capabilities[P_FRAME_MIN_QP].value);
+		CAP_TO_8BIT_QP(inst->capabilities[B_FRAME_MIN_QP].value);
+	} else if (cap_id == MAX_FRAME_QP) {
+		CAP_TO_8BIT_QP(inst->capabilities[I_FRAME_MAX_QP].value);
+		CAP_TO_8BIT_QP(inst->capabilities[P_FRAME_MAX_QP].value);
+		CAP_TO_8BIT_QP(inst->capabilities[B_FRAME_MAX_QP].value);
+	}
+
+exit:
+	return 0;
+}
+
+int msm_vidc_adjust_hevc_min_qp(void *instance, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	if (ctrl)
+		msm_vidc_update_cap_value(inst, MIN_FRAME_QP, ctrl->val, __func__);
+
+	rc = msm_vidc_adjust_hevc_qp(inst, MIN_FRAME_QP);
+
+	return rc;
+}
+
+int msm_vidc_adjust_hevc_max_qp(void *instance, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	if (ctrl)
+		msm_vidc_update_cap_value(inst, MAX_FRAME_QP, ctrl->val, __func__);
+
+	rc = msm_vidc_adjust_hevc_qp(inst, MAX_FRAME_QP);
+
+	return rc;
+}
+
+int msm_vidc_adjust_hevc_i_frame_qp(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	if (ctrl)
+		msm_vidc_update_cap_value(inst, I_FRAME_QP, ctrl->val, __func__);
+
+	return msm_vidc_adjust_hevc_qp(inst, I_FRAME_QP);
+}
+
+int msm_vidc_adjust_hevc_p_frame_qp(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	if (ctrl)
+		msm_vidc_update_cap_value(inst, P_FRAME_QP, ctrl->val, __func__);
+
+	return msm_vidc_adjust_hevc_qp(inst, P_FRAME_QP);
+}
+
+int msm_vidc_adjust_hevc_b_frame_qp(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	if (ctrl)
+		msm_vidc_update_cap_value(inst, B_FRAME_QP, ctrl->val, __func__);
+
+	return msm_vidc_adjust_hevc_qp(inst, B_FRAME_QP);
+}
+
+int msm_vidc_adjust_all_intra(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 gop_size = -1, bframe = -1;
+	u32 width, height, fps, mbps, max_mbps;
+
+	adjusted_value = inst->capabilities[ALL_INTRA].value;
+
+	if (msm_vidc_get_parent_value(inst, ALL_INTRA, GOP_SIZE, &gop_size, __func__) ||
+	    msm_vidc_get_parent_value(inst, ALL_INTRA, B_FRAME, &bframe, __func__))
+		return -EINVAL;
+
+	width = inst->crop.width;
+	height = inst->crop.height;
+	fps =  msm_vidc_get_fps(inst);
+	mbps = NUM_MBS_PER_SEC(height, width, fps);
+	core = inst->core;
+	max_mbps = core->capabilities[MAX_MBPS_ALL_INTRA].value;
+
+	if (mbps > max_mbps) {
+		adjusted_value = 0;
+		i_vpr_h(inst, "%s: mbps %d exceeds max supported mbps %d\n",
+			__func__, mbps, max_mbps);
+		goto exit;
+	}
+
+	if (!gop_size && !bframe)
+		adjusted_value = 1;
+
+exit:
+	msm_vidc_update_cap_value(inst, ALL_INTRA, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_bitrate_boost(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 min_quality = -1, rc_type = -1;
+	u32 max_bitrate = 0, bitrate = 0;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[BITRATE_BOOST].value;
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	if (msm_vidc_get_parent_value(inst, BITRATE_BOOST,
+				      MIN_QUALITY, &min_quality, __func__) ||
+	    msm_vidc_get_parent_value(inst, BITRATE_BOOST,
+				      BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	/*
+	 * Bitrate Boost are supported only for VBR rc type.
+	 * Hence, do not adjust or set to firmware for non VBR rc's
+	 */
+	if (rc_type != HFI_RC_VBR_CFR) {
+		adjusted_value = 0;
+		goto adjust;
+	}
+
+	if (min_quality) {
+		adjusted_value = MAX_BITRATE_BOOST;
+		goto adjust;
+	}
+
+	max_bitrate = msm_vidc_get_max_bitrate(inst);
+	bitrate = inst->capabilities[BIT_RATE].value;
+	if (adjusted_value) {
+		if ((bitrate + bitrate / (100 / adjusted_value)) > max_bitrate) {
+			i_vpr_h(inst,
+				"%s: bitrate %d is beyond max bitrate %d, remove bitrate boost\n",
+				__func__, max_bitrate, bitrate);
+			adjusted_value = 0;
+		}
+	}
+
+adjust:
+	msm_vidc_update_cap_value(inst, BITRATE_BOOST, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_min_quality(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 rc_type = -1, enh_layer_count = -1, pix_fmts = -1;
+	u32 width, height, frame_rate;
+	struct v4l2_format *f;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[MIN_QUALITY].value;
+
+	/*
+	 * Although MIN_QUALITY is static, one of its parents,
+	 * ENH_LAYER_COUNT is dynamic cap. Hence, dynamic call
+	 * may be made for MIN_QUALITY via ENH_LAYER_COUNT.
+	 * Therefore, below streaming check is required to avoid
+	 * runtime modification of MIN_QUALITY.
+	 */
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	if (msm_vidc_get_parent_value(inst, MIN_QUALITY,
+				      BITRATE_MODE, &rc_type, __func__) ||
+	    msm_vidc_get_parent_value(inst, MIN_QUALITY,
+				      ENH_LAYER_COUNT, &enh_layer_count, __func__))
+		return -EINVAL;
+
+	/*
+	 * Min Quality is supported only for VBR rc type.
+	 * Hence, do not adjust or set to firmware for non VBR rc's
+	 */
+	if (rc_type != HFI_RC_VBR_CFR) {
+		adjusted_value = 0;
+		goto update_and_exit;
+	}
+
+	frame_rate = inst->capabilities[FRAME_RATE].value >> 16;
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	/*
+	 * VBR Min Quality not supported for:
+	 * - HEVC 10bit
+	 * - ROI support
+	 * - HP encoding
+	 * - Resolution beyond 1080P
+	 * (It will fall back to CQCAC 25% or 0% (CAC) or CQCAC-OFF)
+	 */
+	if (inst->codec == MSM_VIDC_HEVC) {
+		if (msm_vidc_get_parent_value(inst, MIN_QUALITY,
+					      PIX_FMTS, &pix_fmts, __func__))
+			return -EINVAL;
+
+		if (is_10bit_colorformat(pix_fmts)) {
+			i_vpr_h(inst,
+				"%s: min quality is supported only for 8 bit\n",
+				__func__);
+			adjusted_value = 0;
+			goto update_and_exit;
+		}
+	}
+
+	if (res_is_greater_than(width, height, 1920, 1080)) {
+		i_vpr_h(inst, "%s: unsupported res, wxh %ux%u\n",
+			__func__, width, height);
+		adjusted_value = 0;
+		goto update_and_exit;
+	}
+
+	if (frame_rate > 60) {
+		i_vpr_h(inst, "%s: unsupported fps %u\n",
+			__func__, frame_rate);
+		adjusted_value = 0;
+		goto update_and_exit;
+	}
+
+	if (enh_layer_count > 0 && inst->hfi_layer_type != HFI_HIER_B) {
+		i_vpr_h(inst,
+			"%s: min quality not supported for HP encoding\n",
+			__func__);
+		adjusted_value = 0;
+		goto update_and_exit;
+	}
+
+	/* Above conditions are met. Hence enable min quality */
+	adjusted_value = MAX_SUPPORTED_MIN_QUALITY;
+
+update_and_exit:
+	msm_vidc_update_cap_value(inst, MIN_QUALITY, adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_dec_slice_mode(void *instance, struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 adjusted_value = 0;
+	s32 picture_order = -1;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[SLICE_DECODE].value;
+
+	if (msm_vidc_get_parent_value(inst, SLICE_DECODE, OUTPUT_ORDER,
+				      &picture_order, __func__))
+		return -EINVAL;
+
+	if (!picture_order)
+		adjusted_value = 0;
+
+	msm_vidc_update_cap_value(inst, SLICE_DECODE,
+				  adjusted_value, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_ir_period(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value, all_intra = 0,
+		pix_fmts = MSM_VIDC_FMT_NONE;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	adjusted_value = ctrl ? ctrl->val : inst->capabilities[IR_PERIOD].value;
+
+	if (msm_vidc_get_parent_value(inst, IR_PERIOD, ALL_INTRA,
+				      &all_intra, __func__))
+		return -EINVAL;
+
+	if (all_intra) {
+		adjusted_value = 0;
+		i_vpr_h(inst, "%s: intra refresh unsupported, all intra: %d\n",
+			__func__, all_intra);
+		goto exit;
+	}
+
+	if (inst->codec == MSM_VIDC_HEVC) {
+		if (msm_vidc_get_parent_value(inst, IR_PERIOD,
+					      PIX_FMTS, &pix_fmts, __func__))
+			return -EINVAL;
+
+		if (is_10bit_colorformat(pix_fmts)) {
+			i_vpr_h(inst,
+				"%s: intra refresh is supported only for 8 bit\n",
+				__func__);
+			adjusted_value = 0;
+			goto exit;
+		}
+	}
+
+	/*
+	 * BITRATE_MODE dependency is NOT common across all chipsets.
+	 * Hence, do not return error if not specified as one of the parent.
+	 */
+	if (is_parent_available(inst, IR_PERIOD, BITRATE_MODE, __func__) &&
+	    inst->hfi_rc_type != HFI_RC_CBR_CFR &&
+	    inst->hfi_rc_type != HFI_RC_CBR_VFR)
+		adjusted_value = 0;
+
+exit:
+	msm_vidc_update_cap_value(inst, IR_PERIOD, adjusted_value, __func__);
+
+	return 0;
+}
+
+/******************* End of Control Adjust functions *************************/
+
+/************************* Control Set functions *****************************/
+
+int msm_vidc_set_header_mode(void *instance,
+			     enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	int header_mode, prepend_sps_pps;
+	u32 hfi_value = 0;
+
+	header_mode = inst->capabilities[cap_id].value;
+	prepend_sps_pps = inst->capabilities[PREPEND_SPSPPS_TO_IDR].value;
+
+	/* prioritize PREPEND_SPSPPS_TO_IDR mode over other header modes */
+	if (prepend_sps_pps)
+		hfi_value = HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME;
+	else if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME)
+		hfi_value = HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME;
+	else
+		hfi_value = HFI_SEQ_HEADER_SEPERATE_FRAME;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_deblock_mode(void *instance, enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 alpha = 0, beta = 0;
+	u32 lf_mode, hfi_value = 0, lf_offset = 6;
+
+	rc = msm_vidc_v4l2_to_hfi_enum(inst, LF_MODE, &lf_mode);
+	if (rc)
+		return -EINVAL;
+
+	beta = inst->capabilities[LF_BETA].value + lf_offset;
+	alpha = inst->capabilities[LF_ALPHA].value + lf_offset;
+	hfi_value = (alpha << 16) | (beta << 8) | lf_mode;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_constant_quality(void *instance, enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+	s32 rc_type = -1;
+
+	if (msm_vidc_get_parent_value(inst, cap_id, BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if (rc_type != HFI_RC_CQ)
+		return 0;
+
+	hfi_value = inst->capabilities[cap_id].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_cbr_related_properties(void *instance,
+					enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+	s32 rc_type = -1;
+
+	if (msm_vidc_get_parent_value(inst, cap_id, BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if (rc_type != HFI_RC_CBR_VFR &&
+	    rc_type != HFI_RC_CBR_CFR)
+		return 0;
+
+	hfi_value = inst->capabilities[cap_id].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_use_and_mark_ltr(void *instance,
+				  enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+
+	if (!inst->capabilities[LTR_COUNT].value ||
+	    inst->capabilities[cap_id].value ==
+	     INVALID_DEFAULT_MARK_OR_USE_LTR) {
+		i_vpr_h(inst,
+			"%s: LTR_COUNT: %d %s: %d, cap %s is not set\n",
+			__func__, inst->capabilities[LTR_COUNT].value,
+			cap_name(cap_id),
+			inst->capabilities[cap_id].value,
+			cap_name(cap_id));
+		return 0;
+	}
+
+	hfi_value = inst->capabilities[cap_id].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_min_qp(void *instance,
+			enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0, min_qp_enable = 0;
+	u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0;
+	u32 client_qp_enable = 0, hfi_value = 0, offset = 0;
+
+	if (inst->capabilities[MIN_FRAME_QP].flags & CAP_FLAG_CLIENT_SET)
+		min_qp_enable = 1;
+
+	if (min_qp_enable ||
+	    (inst->capabilities[I_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET))
+		i_qp_enable = 1;
+	if (min_qp_enable ||
+	    (inst->capabilities[P_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET))
+		p_qp_enable = 1;
+	if (min_qp_enable ||
+	    (inst->capabilities[B_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET))
+		b_qp_enable = 1;
+
+	client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2;
+	if (!client_qp_enable) {
+		i_vpr_h(inst,
+			"%s: client did not set min qp, cap %s is not set\n",
+			__func__, cap_name(cap_id));
+		return 0;
+	}
+
+	if (is_10bit_colorformat(inst->capabilities[PIX_FMTS].value))
+		offset = 12;
+
+	/*
+	 * I_FRAME_MIN_QP, P_FRAME_MIN_QP, B_FRAME_MIN_QP,
+	 * MIN_FRAME_QP caps have default value as MIN_QP_10BIT values.
+	 * Hence, if client sets either one among MIN_FRAME_QP
+	 * and (I_FRAME_MIN_QP or P_FRAME_MIN_QP or B_FRAME_MIN_QP),
+	 * max of both caps will result into client set value.
+	 */
+	i_frame_qp = max(inst->capabilities[I_FRAME_MIN_QP].value,
+			 inst->capabilities[MIN_FRAME_QP].value) + offset;
+	p_frame_qp = max(inst->capabilities[P_FRAME_MIN_QP].value,
+			 inst->capabilities[MIN_FRAME_QP].value) + offset;
+	b_frame_qp = max(inst->capabilities[B_FRAME_MIN_QP].value,
+			 inst->capabilities[MIN_FRAME_QP].value) + offset;
+
+	hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 |
+		client_qp_enable << 24;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_max_qp(void *instance,
+			enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0, max_qp_enable = 0;
+	u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0;
+	u32 client_qp_enable = 0, hfi_value = 0, offset = 0;
+
+	if (inst->capabilities[MAX_FRAME_QP].flags & CAP_FLAG_CLIENT_SET)
+		max_qp_enable = 1;
+
+	if (max_qp_enable ||
+	    (inst->capabilities[I_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET))
+		i_qp_enable = 1;
+	if (max_qp_enable ||
+	    (inst->capabilities[P_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET))
+		p_qp_enable = 1;
+	if (max_qp_enable ||
+	    (inst->capabilities[B_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET))
+		b_qp_enable = 1;
+
+	client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2;
+	if (!client_qp_enable) {
+		i_vpr_h(inst,
+			"%s: client did not set max qp, cap %s is not set\n",
+			__func__, cap_name(cap_id));
+		return 0;
+	}
+
+	if (is_10bit_colorformat(inst->capabilities[PIX_FMTS].value))
+		offset = 12;
+
+	/*
+	 * I_FRAME_MAX_QP, P_FRAME_MAX_QP, B_FRAME_MAX_QP,
+	 * MAX_FRAME_QP caps have default value as MAX_QP values.
+	 * Hence, if client sets either one among MAX_FRAME_QP
+	 * and (I_FRAME_MAX_QP or P_FRAME_MAX_QP or B_FRAME_MAX_QP),
+	 * min of both caps will result into client set value.
+	 */
+	i_frame_qp = min(inst->capabilities[I_FRAME_MAX_QP].value,
+			 inst->capabilities[MAX_FRAME_QP].value) + offset;
+	p_frame_qp = min(inst->capabilities[P_FRAME_MAX_QP].value,
+			 inst->capabilities[MAX_FRAME_QP].value) + offset;
+	b_frame_qp = min(inst->capabilities[B_FRAME_MAX_QP].value,
+			 inst->capabilities[MAX_FRAME_QP].value) + offset;
+
+	hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 |
+		client_qp_enable << 24;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_frame_qp(void *instance,
+			  enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	struct msm_vidc_inst_cap *capab;
+	s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0;
+	u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0;
+	u32 client_qp_enable = 0, hfi_value = 0, offset = 0;
+	s32 rc_type = -1;
+
+	capab = inst->capabilities;
+
+	if (msm_vidc_get_parent_value(inst, cap_id,
+				      BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		if (rc_type != HFI_RC_OFF) {
+			i_vpr_h(inst,
+				"%s: dynamic qp not allowed for rc type %d\n",
+				__func__, rc_type);
+			return 0;
+		}
+	}
+
+	if (rc_type == HFI_RC_OFF) {
+		/* Mandatorily set for rc off case */
+		i_qp_enable = 1;
+		p_qp_enable = 1;
+		b_qp_enable = 1;
+	} else {
+		/* Set only if client has set for NON rc off case */
+		if (capab[I_FRAME_QP].flags & CAP_FLAG_CLIENT_SET)
+			i_qp_enable = 1;
+		if (capab[P_FRAME_QP].flags & CAP_FLAG_CLIENT_SET)
+			p_qp_enable = 1;
+		if (capab[B_FRAME_QP].flags & CAP_FLAG_CLIENT_SET)
+			b_qp_enable = 1;
+	}
+
+	client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2;
+	if (!client_qp_enable) {
+		i_vpr_h(inst,
+			"%s: client did not set frame qp, cap %s is not set\n",
+			__func__, cap_name(cap_id));
+		return 0;
+	}
+
+	if (is_10bit_colorformat(capab[PIX_FMTS].value))
+		offset = 12;
+
+	i_frame_qp = capab[I_FRAME_QP].value + offset;
+	p_frame_qp = capab[P_FRAME_QP].value + offset;
+	b_frame_qp = capab[B_FRAME_QP].value + offset;
+
+	hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 |
+		client_qp_enable << 24;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_req_sync_frame(void *instance,
+				enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 prepend_spspps;
+	u32 hfi_value = 0;
+
+	prepend_spspps = inst->capabilities[PREPEND_SPSPPS_TO_IDR].value;
+	if (prepend_spspps)
+		hfi_value = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR;
+	else
+		hfi_value = HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_chroma_qp_index_offset(void *instance,
+					enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0, chroma_qp_offset_mode = 0, chroma_qp = 0;
+	u32 offset = 12;
+
+	if (inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)
+		chroma_qp_offset_mode = HFI_FIXED_CHROMAQP_OFFSET;
+	else
+		chroma_qp_offset_mode = HFI_ADAPTIVE_CHROMAQP_OFFSET;
+
+	chroma_qp = inst->capabilities[cap_id].value + offset;
+	hfi_value = chroma_qp_offset_mode | chroma_qp << 8 | chroma_qp << 16;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_slice_count(void *instance,
+			     enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 slice_mode = -1;
+	u32 hfi_value = 0, set_cap_id = 0;
+
+	slice_mode = inst->capabilities[SLICE_MODE].value;
+
+	if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) {
+		i_vpr_h(inst, "%s: slice mode is: %u, ignore setting to fw\n",
+			__func__, slice_mode);
+		return 0;
+	}
+	if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
+		hfi_value = (inst->codec == MSM_VIDC_HEVC) ?
+			((inst->capabilities[SLICE_MAX_MB].value + 3) / 4) :
+			inst->capabilities[SLICE_MAX_MB].value;
+		set_cap_id = SLICE_MAX_MB;
+	} else if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
+		hfi_value = inst->capabilities[SLICE_MAX_BYTES].value;
+		set_cap_id = SLICE_MAX_BYTES;
+	}
+
+	return msm_vidc_packetize_control(inst, set_cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_nal_length(void *instance,
+			    enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = HFI_NAL_LENGTH_STARTCODES;
+
+	if (!inst->capabilities[WITHOUT_STARTCODE].value) {
+		hfi_value = HFI_NAL_LENGTH_STARTCODES;
+	} else {
+		rc = msm_vidc_v4l2_to_hfi_enum(inst, NAL_LENGTH_FIELD, &hfi_value);
+		if (rc)
+			return -EINVAL;
+	}
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_layer_count_and_type(void *instance,
+				      enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_layer_count, hfi_layer_type = 0;
+
+	if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		/* set layer type */
+		hfi_layer_type = inst->hfi_layer_type;
+		cap_id = LAYER_TYPE;
+
+		rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+						&hfi_layer_type, sizeof(u32), __func__);
+		if (rc)
+			goto exit;
+	} else {
+		if (inst->hfi_layer_type == HFI_HIER_B) {
+			i_vpr_l(inst,
+				"%s: HB dyn layers change is not supported\n",
+				__func__);
+			return 0;
+		}
+	}
+
+	/* set layer count */
+	cap_id = ENH_LAYER_COUNT;
+	/* hfi baselayer starts from 1 */
+	hfi_layer_count = inst->capabilities[ENH_LAYER_COUNT].value + 1;
+
+	rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_layer_count, sizeof(u32), __func__);
+	if (rc)
+		goto exit;
+
+exit:
+	return rc;
+}
+
+int msm_vidc_set_gop_size(void *instance,
+			  enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		if (inst->hfi_layer_type == HFI_HIER_B) {
+			i_vpr_l(inst,
+				"%s: HB dyn GOP setting is not supported\n",
+				__func__);
+			return 0;
+		}
+	}
+
+	hfi_value = inst->capabilities[GOP_SIZE].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_bitrate(void *instance,
+			 enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+
+	/* set Total Bitrate */
+	if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET)
+		goto set_total_bitrate;
+
+	/*
+	 * During runtime, if BIT_RATE cap CLIENT_SET flag is not set,
+	 * then this function will be called due to change in ENH_LAYER_COUNT.
+	 * In this case, client did not change bitrate, hence, no need to set
+	 * to fw.
+	 */
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+set_total_bitrate:
+	hfi_value = inst->capabilities[BIT_RATE].value;
+	return msm_vidc_packetize_control(inst, BIT_RATE, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_layer_bitrate(void *instance,
+			       enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+
+	if (!inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	/* set Total Bitrate */
+	if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) {
+		i_vpr_h(inst,
+			"%s: Total bitrate is set, ignore layer bitrate\n",
+			__func__);
+		return 0;
+	}
+
+	/*
+	 * ENH_LAYER_COUNT cap max is positive only if
+	 *    layer encoding is enabled during streamon.
+	 */
+	if (!inst->capabilities[ENH_LAYER_COUNT].max ||
+	    !msm_vidc_check_all_layer_bitrate_set(inst)) {
+		i_vpr_h(inst,
+			"%s: invalid layer bitrate, ignore setting to fw\n",
+			__func__);
+		return 0;
+	}
+
+	/*
+	 * Accept layerwise bitrate but set total bitrate which was already
+	 * adjusted based on layer bitrate
+	 */
+	hfi_value = inst->capabilities[BIT_RATE].value;
+	return msm_vidc_packetize_control(inst, BIT_RATE, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_flip(void *instance,
+		      enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	u32 hflip, vflip, hfi_value = HFI_DISABLE_FLIP;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	hflip = inst->capabilities[HFLIP].value;
+	vflip = inst->capabilities[VFLIP].value;
+
+	if (hflip)
+		hfi_value |= HFI_HORIZONTAL_FLIP;
+
+	if (vflip)
+		hfi_value |= HFI_VERTICAL_FLIP;
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+		if (hfi_value != HFI_DISABLE_FLIP) {
+			rc = msm_vidc_set_req_sync_frame(inst, REQUEST_I_FRAME);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_rotation(void *instance,
+			  enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	rc = msm_vidc_v4l2_to_hfi_enum(inst, cap_id, &hfi_value);
+	if (rc)
+		return -EINVAL;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_level(void *instance,
+		       enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+
+	hfi_value = inst->capabilities[cap_id].value;
+	if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET))
+		hfi_value = HFI_LEVEL_NONE;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_ir_period(void *instance,
+			   enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 ir_type = 0;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+
+	if (inst->capabilities[IR_TYPE].value ==
+	    V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) {
+		if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
+			i_vpr_h(inst, "%s: dynamic random intra refresh not allowed\n",
+				__func__);
+			return 0;
+		}
+		ir_type = HFI_PROP_IR_RANDOM_PERIOD;
+	} else if (inst->capabilities[IR_TYPE].value ==
+		   V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) {
+		ir_type = HFI_PROP_IR_CYCLIC_PERIOD;
+	} else {
+		i_vpr_e(inst, "%s: invalid ir_type %d\n",
+			__func__, inst->capabilities[IR_TYPE].value);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_set_ir_period(inst, ir_type, cap_id);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed to set ir period %d\n",
+			__func__, inst->capabilities[IR_PERIOD].value);
+		return rc;
+	}
+
+	return rc;
+}
+
+int msm_vidc_set_q16(void *instance,
+		     enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value = 0;
+
+	hfi_value = inst->capabilities[cap_id].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_Q16,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_u32(void *instance,
+		     enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	if (inst->capabilities[cap_id].flags & CAP_FLAG_MENU) {
+		rc = msm_vidc_v4l2_menu_to_hfi(inst, cap_id, &hfi_value);
+		if (rc)
+			return -EINVAL;
+	} else {
+		hfi_value = inst->capabilities[cap_id].value;
+	}
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_u32_packed(void *instance,
+			    enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	if (inst->capabilities[cap_id].flags & CAP_FLAG_MENU) {
+		rc = msm_vidc_v4l2_menu_to_hfi(inst, cap_id, &hfi_value);
+		if (rc)
+			return -EINVAL;
+	} else {
+		hfi_value = inst->capabilities[cap_id].value;
+	}
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_u32_enum(void *instance,
+			  enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	rc = msm_vidc_v4l2_to_hfi_enum(inst, cap_id, &hfi_value);
+	if (rc)
+		return -EINVAL;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_s32(void *instance,
+		     enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 hfi_value = 0;
+
+	hfi_value = inst->capabilities[cap_id].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_S32,
+					&hfi_value, sizeof(s32), __func__);
+}
+
+int msm_vidc_set_stage(void *instance,
+		       enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	u32 stage = 0;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	core = inst->core;
+
+	rc = call_session_op(core, decide_work_mode, inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: decide_work_mode failed\n", __func__);
+		return -EINVAL;
+	}
+
+	stage = inst->capabilities[STAGE].value;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&stage, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_pipe(void *instance,
+		      enum msm_vidc_inst_capability_type cap_id)
+{
+	int rc = 0;
+	u32 pipe;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+
+	core = inst->core;
+
+	rc = call_session_op(core, decide_work_route, inst);
+	if (rc) {
+		i_vpr_e(inst, "%s: decide_work_route failed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	pipe = inst->capabilities[PIPE].value;
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&pipe, sizeof(u32), __func__);
+}
+
+int msm_vidc_set_vui_timing_info(void *instance,
+				 enum msm_vidc_inst_capability_type cap_id)
+{
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	u32 hfi_value;
+
+	/*
+	 * hfi is HFI_PROP_DISABLE_VUI_TIMING_INFO and v4l2 cap is
+	 * V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO and hence reverse
+	 * the hfi_value from cap_id value.
+	 */
+	if (inst->capabilities[cap_id].value == 1)
+		hfi_value = 0;
+	else
+		hfi_value = 1;
+
+	return msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32,
+					&hfi_value, sizeof(u32), __func__);
+}
+
+/********************* End of Control Set functions **************************/
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (24 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 25/33] iris: platform: add platform files Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 14:13   ` Dmitry Baryshkov
  2023-07-28 13:23 ` [PATCH 27/33] iris: variant: add helper functions for register handling Vikash Garodia
                   ` (9 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements all the capabilities supported by sm8550.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
 .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++++++++++++++
 2 files changed, 1741 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
 create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c

diff --git a/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
new file mode 100644
index 0000000..0a2f172
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_SM8550_H_
+#define _MSM_VIDC_SM8550_H_
+
+#include "msm_vidc_core.h"
+
+int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core);
+
+#endif // _MSM_VIDC_SM8550_H_
diff --git a/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
new file mode 100644
index 0000000..2408556
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
@@ -0,0 +1,1727 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/clock/qcom,sm8550-gcc.h>
+#include <dt-bindings/clock/qcom,sm8450-videocc.h>
+
+#include "hfi_command.h"
+#include "hfi_property.h"
+#include "msm_vidc_control.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_iris3.h"
+#include "msm_vidc_sm8550.h"
+#include "msm_vidc_platform.h"
+
+/* version: major[24:31], minor[16:23], revision[0:15] */
+#define DRIVER_VERSION          0x04000000
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
+#define MAX_BASE_LAYER_PRIORITY_ID 63
+#define MAX_OP_POINT            31
+#define MAX_BITRATE             245000000
+#define DEFAULT_BITRATE         20000000
+#define MINIMUM_FPS             1
+#define MAXIMUM_FPS             480
+#define MAXIMUM_DEC_FPS         960
+#define MAX_QP                  51
+#define DEFAULT_QP              20
+#define MAX_CONSTANT_QUALITY    100
+#define MIN_SLICE_BYTE_SIZE     512
+#define MAX_SLICE_BYTE_SIZE       \
+	((MAX_BITRATE) >> 3)
+#define MAX_SLICE_MB_SIZE         \
+	(((4096 + 15) >> 4) * ((2304 + 15) >> 4))
+
+#define ENC     MSM_VIDC_ENCODER
+#define DEC     MSM_VIDC_DECODER
+#define H264    MSM_VIDC_H264
+#define HEVC    MSM_VIDC_HEVC
+#define VP9     MSM_VIDC_VP9
+#define CODECS_ALL     (H264 | HEVC | VP9)
+#define MAXIMUM_OVERRIDE_VP9_FPS 200
+
+static struct codec_info codec_data_sm8550[] = {
+	{
+		.v4l2_codec  = V4L2_PIX_FMT_H264,
+		.vidc_codec  = MSM_VIDC_H264,
+		.pixfmt_name = "AVC",
+	},
+	{
+		.v4l2_codec  = V4L2_PIX_FMT_HEVC,
+		.vidc_codec  = MSM_VIDC_HEVC,
+		.pixfmt_name = "HEVC",
+	},
+	{
+		.v4l2_codec  = V4L2_PIX_FMT_VP9,
+		.vidc_codec  = MSM_VIDC_VP9,
+		.pixfmt_name = "VP9",
+	},
+};
+
+static struct color_format_info color_format_data_sm8550[] = {
+	{
+		.v4l2_color_format = V4L2_PIX_FMT_NV12,
+		.vidc_color_format = MSM_VIDC_FMT_NV12,
+		.pixfmt_name       = "NV12",
+	},
+	{
+		.v4l2_color_format = V4L2_PIX_FMT_NV21,
+		.vidc_color_format = MSM_VIDC_FMT_NV21,
+		.pixfmt_name       = "NV21",
+	},
+	{
+		.v4l2_color_format = V4L2_PIX_FMT_QC08C,
+		.vidc_color_format = MSM_VIDC_FMT_NV12C,
+		.pixfmt_name       = "NV12C",
+	},
+	{
+		.v4l2_color_format = V4L2_PIX_FMT_QC10C,
+		.vidc_color_format = MSM_VIDC_FMT_TP10C,
+		.pixfmt_name       = "TP10C",
+	},
+	{
+		.v4l2_color_format = V4L2_PIX_FMT_RGBA32,
+		.vidc_color_format = MSM_VIDC_FMT_RGBA8888,
+		.pixfmt_name       = "RGBA",
+	},
+};
+
+static struct color_primaries_info color_primaries_data_sm8550[] = {
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_DEFAULT,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_RESERVED,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_REC709,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT709,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_M,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_BG,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE170M,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT601_525,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE240M,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_ST240M,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_BT2020,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT2020,
+	},
+	{
+		.v4l2_color_primaries  = V4L2_COLORSPACE_DCI_P3,
+		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_RP431_2,
+	},
+};
+
+static struct transfer_char_info transfer_char_data_sm8550[] = {
+	{
+		.v4l2_transfer_char  = V4L2_XFER_FUNC_DEFAULT,
+		.vidc_transfer_char  = MSM_VIDC_TRANSFER_RESERVED,
+	},
+	{
+		.v4l2_transfer_char  = V4L2_XFER_FUNC_709,
+		.vidc_transfer_char  = MSM_VIDC_TRANSFER_BT709,
+	},
+	{
+		.v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE240M,
+		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST240M,
+	},
+	{
+		.v4l2_transfer_char  = V4L2_XFER_FUNC_SRGB,
+		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SRGB_SYCC,
+	},
+	{
+		.v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE2084,
+		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ,
+	},
+};
+
+static struct matrix_coeff_info matrix_coeff_data_sm8550[] = {
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_DEFAULT,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_RESERVED,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_709,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV709,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV601,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_601,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_SMPTE240M,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT,
+	},
+	{
+		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020_CONST_LUM,
+		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT,
+	},
+};
+
+static struct msm_platform_core_capability core_data_sm8550[] = {
+	/* {type, value} */
+	{ENC_CODECS, H264 | HEVC},
+	{DEC_CODECS, H264 | HEVC | VP9},
+	{MAX_SESSION_COUNT, 16},
+	{MAX_NUM_720P_SESSIONS, 16},
+	{MAX_NUM_1080P_SESSIONS, 16},
+	{MAX_NUM_4K_SESSIONS, 8},
+	{MAX_NUM_8K_SESSIONS, 2},
+	{MAX_RT_MBPF, 174080},	/* (8192x4352)/256 + (4096x2176)/256*/
+	{MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */
+	{MAX_MBPS, 7833600},	/* max_load
+				 * 7680x4320@60fps or 3840x2176@240fps
+				 * which is greater than 4096x2176@120fps,
+				 * 8192x4320@48fps
+				 */
+	{MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */
+	{MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */
+	{MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */
+	{MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */
+	{MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */
+	{MAX_ENH_LAYER_COUNT, 5},
+	{NUM_VPP_PIPE, 4},
+	{SW_PC, 1},
+	{FW_UNLOAD, 0},
+	{HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */
+	{SW_PC_DELAY,         SW_PC_DELAY_VALUE        }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/
+	{FW_UNLOAD_DELAY,     FW_UNLOAD_DELAY_VALUE    }, /* 3000 ms (>SW_PC_DELAY)*/
+	{DCVS, 1},
+	{DECODE_BATCH, 1},
+	{DECODE_BATCH_TIMEOUT, 200},
+	{STATS_TIMEOUT_MS, 2000},
+	{NON_FATAL_FAULTS, 1},
+	{DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING},
+};
+
+static struct msm_platform_inst_capability instance_cap_data_sm8550[] = {
+	/* {cap, domain, codec,
+	 *      min, max, step_or_mask, value,
+	 *      v4l2_id,
+	 *      hfi_id,
+	 *      flags}
+	 */
+	{FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920},
+
+	{FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920},
+
+	{FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920},
+
+	{FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920},
+
+	{LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920},
+
+	{LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920},
+
+	{FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080},
+
+	{FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080},
+
+	{FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080},
+
+	{FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080},
+
+	{LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080},
+
+	{LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080},
+
+	{PIX_FMTS, ENC | DEC, H264,
+		MSM_VIDC_FMT_NV12,
+		MSM_VIDC_FMT_NV12C,
+		MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C,
+		MSM_VIDC_FMT_NV12C},
+
+	{PIX_FMTS, ENC | DEC, HEVC | VP9,
+		MSM_VIDC_FMT_NV12,
+		MSM_VIDC_FMT_TP10C,
+		MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C |
+		MSM_VIDC_FMT_TP10C,
+		MSM_VIDC_FMT_NV12C},
+
+	{MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4,
+		V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+		0,
+		CAP_FLAG_VOLATILE},
+
+	{MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL,
+		0, 64, 1, 4,
+		V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+		HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE},
+
+	/* (8192 * 4320) / 256 */
+	{MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240},
+
+	{MBPF, ENC, HEVC, 36, 138240, 1, 138240},
+
+	{MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240},
+
+	/* (4096 * 2304) / 256 */
+	{MBPF, DEC, VP9, 36, 36864, 1, 36864},
+
+	/* (4096 * 2304) / 256 */
+	{LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864},
+
+	/* Batch Mode Decode */
+	/* TODO: update with new values based on updated voltage corner */
+	{BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816},
+
+	/* (4096 * 2304) / 256 */
+	{BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120},
+
+	{FRAME_RATE, ENC | DEC, CODECS_ALL,
+		(MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
+		1, (DEFAULT_FPS << 16),
+		0,
+		HFI_PROP_FRAME_RATE,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{OPERATING_RATE, ENC | DEC, CODECS_ALL,
+		(MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
+		1, (DEFAULT_FPS << 16)},
+
+	{INPUT_RATE, ENC | DEC, CODECS_ALL,
+		(MINIMUM_FPS << 16), INT_MAX,
+		1, (DEFAULT_FPS << 16)},
+
+	{TIMESTAMP_RATE, ENC | DEC, CODECS_ALL,
+		(MINIMUM_FPS << 16), INT_MAX,
+		1, (DEFAULT_FPS << 16)},
+
+	{SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8},
+
+	{MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25},
+
+	{MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25},
+
+	{MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60},
+
+	{MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675},
+
+	{MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200},
+
+	{MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320},
+
+	{MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200},
+
+	{MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583},
+
+	{MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405},
+
+	{MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234},
+
+	{HFLIP, ENC, CODECS_ALL,
+		0, 1, 1, 0,
+		V4L2_CID_HFLIP,
+		HFI_PROP_FLIP,
+		CAP_FLAG_OUTPUT_PORT |
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{VFLIP, ENC, CODECS_ALL,
+		0, 1, 1, 0,
+		V4L2_CID_VFLIP,
+		HFI_PROP_FLIP,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+		CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{ROTATION, ENC, CODECS_ALL,
+		0, 270, 90, 0,
+		V4L2_CID_ROTATE,
+		HFI_PROP_ROTATION,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{HEADER_MODE, ENC, CODECS_ALL,
+		V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+		BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+		BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
+		V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		HFI_PROP_SEQ_HEADER_MODE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR},
+
+	{WITHOUT_STARTCODE, ENC, CODECS_ALL,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
+		HFI_PROP_NAL_LENGTH_FIELD,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{NAL_LENGTH_FIELD, ENC, CODECS_ALL,
+		V4L2_MPEG_VIDEO_HEVC_SIZE_0,
+		V4L2_MPEG_VIDEO_HEVC_SIZE_4,
+		BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4),
+		V4L2_MPEG_VIDEO_HEVC_SIZE_0,
+		V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
+		HFI_PROP_NAL_LENGTH_FIELD,
+		CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT},
+
+	/* TODO: Firmware introduced enumeration type for this
+	 * with and without seq header.
+	 */
+	{REQUEST_I_FRAME, ENC, H264 | HEVC,
+		0, 0, 0, 0,
+		V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
+		HFI_PROP_REQUEST_SYNC_FRAME,
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
+
+	/* Enc: Keeping CABAC and CAVLC as same bitrate.
+	 * Dec: there's no use of Bitrate cap
+	 */
+	{BIT_RATE, ENC, H264 | HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_BITRATE,
+		HFI_PROP_TOTAL_BITRATE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+		CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{BITRATE_MODE, ENC, H264,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
+		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		HFI_PROP_RATE_CONTROL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{BITRATE_MODE, ENC, HEVC,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CQ,
+		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
+		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ),
+		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		HFI_PROP_RATE_CONTROL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0,
+		160000000, 1, 160000000},
+
+	{CAVLC_MAX_BITRATE, ENC, H264, 0,
+		220000000, 1, 220000000},
+
+	{ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0,
+		245000000, 1, 245000000},
+
+	{NUM_COMV, DEC, CODECS_ALL,
+		0, INT_MAX, 1, 0},
+
+	{LOSSLESS, ENC, HEVC,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU},
+
+	{FRAME_SKIP_MODE, ENC, H264 | HEVC,
+		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
+		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) |
+		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
+		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+		V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
+		0,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{FRAME_RC_ENABLE, ENC, H264 | HEVC,
+		0, 1, 1, 1,
+		V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE},
+
+	{CONSTANT_QUALITY, ENC, HEVC,
+		1, MAX_CONSTANT_QUALITY, 1, 90,
+		V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY,
+		HFI_PROP_CONSTANT_QUALITY,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+		CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{GOP_SIZE, ENC, CODECS_ALL,
+		0, INT_MAX, 1, 2 * DEFAULT_FPS - 1,
+		V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+		HFI_PROP_MAX_GOP_FRAMES,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+		CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{GOP_CLOSURE, ENC, H264 | HEVC,
+		0, 1, 1, 1,
+		V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+		0},
+
+	{B_FRAME, ENC, H264 | HEVC,
+		0, 7, 1, 0,
+		V4L2_CID_MPEG_VIDEO_B_FRAMES,
+		HFI_PROP_MAX_B_FRAMES,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{LTR_COUNT, ENC, H264 | HEVC,
+		0, MAX_LTR_FRAME_COUNT_2, 1, 0,
+		V4L2_CID_MPEG_VIDEO_LTR_COUNT,
+		HFI_PROP_LTR_COUNT,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{USE_LTR, ENC, H264 | HEVC,
+		0,
+		((1 << MAX_LTR_FRAME_COUNT_2) - 1),
+		0, 0,
+		V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES,
+		HFI_PROP_LTR_USE,
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{MARK_LTR, ENC, H264 | HEVC,
+		INVALID_DEFAULT_MARK_OR_USE_LTR,
+		(MAX_LTR_FRAME_COUNT_2 - 1),
+		1, INVALID_DEFAULT_MARK_OR_USE_LTR,
+		V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX,
+		HFI_PROP_LTR_MARK,
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{BASELAYER_PRIORITY, ENC, H264,
+		0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0,
+		V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID,
+		HFI_PROP_BASELAYER_PRIORITYID,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{IR_TYPE, ENC, H264 | HEVC,
+		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
+		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
+		BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) |
+		BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC),
+		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
+		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
+		0,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{IR_PERIOD, ENC, H264 | HEVC,
+		0, INT_MAX, 1, 0,
+		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
+		0,
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT |
+		CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{AU_DELIMITER, ENC, H264 | HEVC,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
+		HFI_PROP_AUD,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{MIN_QUALITY, ENC, H264 | HEVC,
+		0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY,
+		0,
+		HFI_PROP_MAINTAIN_MIN_QUALITY,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{VBV_DELAY, ENC, H264 | HEVC,
+		200, 300, 100, 300,
+		V4L2_CID_MPEG_VIDEO_VBV_DELAY,
+		HFI_PROP_VBV_DELAY,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{PEAK_BITRATE, ENC, H264 | HEVC,
+		/* default peak bitrate is 10% larger than avg bitrate */
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		HFI_PROP_TOTAL_PEAK_BITRATE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{MIN_FRAME_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
+		V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+		HFI_PROP_MIN_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{MIN_FRAME_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
+		V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+		HFI_PROP_MIN_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{I_FRAME_MIN_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
+		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP},
+
+	{I_FRAME_MIN_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
+		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP},
+
+	{P_FRAME_MIN_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
+		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP},
+
+	{P_FRAME_MIN_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
+		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP},
+
+	{B_FRAME_MIN_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
+		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP},
+
+	{B_FRAME_MIN_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
+		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP},
+
+	{MAX_FRAME_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+		HFI_PROP_MAX_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{MAX_FRAME_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+		HFI_PROP_MAX_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{I_FRAME_MAX_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP},
+
+	{I_FRAME_MAX_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP},
+
+	{P_FRAME_MAX_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP},
+
+	{P_FRAME_MAX_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP},
+
+	{B_FRAME_MAX_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP},
+
+	{B_FRAME_MAX_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP},
+
+	{I_FRAME_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{I_FRAME_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{P_FRAME_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{P_FRAME_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{B_FRAME_QP, ENC, HEVC,
+		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{B_FRAME_QP, ENC, H264,
+		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
+		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+		HFI_PROP_QP_PACKED,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{LAYER_TYPE, ENC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
+		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
+		BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P),
+		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
+		HFI_PROP_LAYER_ENCODING_TYPE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LAYER_TYPE, ENC, H264,
+		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
+		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+		BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) |
+		BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P),
+		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
+		HFI_PROP_LAYER_ENCODING_TYPE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LAYER_ENABLE, ENC, H264,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
+		HFI_PROP_LAYER_ENCODING_TYPE,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{LAYER_ENABLE, ENC, HEVC,
+		0, 1, 1, 0,
+		0,
+		0,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{ENH_LAYER_COUNT, ENC, HEVC,
+		0, 5, 1, 0,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
+		HFI_PROP_LAYER_COUNT,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{ENH_LAYER_COUNT, ENC, H264,
+		0, 5, 1, 0,
+		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
+		HFI_PROP_LAYER_COUNT,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L0_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
+		HFI_PROP_BITRATE_LAYER1,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L0_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
+		HFI_PROP_BITRATE_LAYER1,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L1_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
+		HFI_PROP_BITRATE_LAYER2,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L1_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
+		HFI_PROP_BITRATE_LAYER2,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L2_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
+		HFI_PROP_BITRATE_LAYER3,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L2_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
+		HFI_PROP_BITRATE_LAYER3,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L3_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
+		HFI_PROP_BITRATE_LAYER4,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+	{L3_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
+		HFI_PROP_BITRATE_LAYER4,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L4_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
+		HFI_PROP_BITRATE_LAYER5,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L4_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
+		HFI_PROP_BITRATE_LAYER5,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L5_BR, ENC, H264,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
+		HFI_PROP_BITRATE_LAYER6,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{L5_BR, ENC, HEVC,
+		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
+		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
+		HFI_PROP_BITRATE_LAYER6,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+			CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{ENTROPY_MODE, ENC, H264,
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		HFI_PROP_CABAC_SESSION,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{ENTROPY_MODE, DEC, H264 | HEVC | VP9,
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
+		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		0,
+		HFI_PROP_CABAC_SESSION},
+
+	{PROFILE, ENC | DEC, H264,
+		V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) |
+		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH),
+		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+		V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		HFI_PROP_PROFILE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{PROFILE, ENC | DEC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10),
+		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		HFI_PROP_PROFILE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{PROFILE, DEC, VP9,
+		V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+		V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2),
+		V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+		V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+		HFI_PROP_PROFILE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LEVEL, ENC, H264,
+		V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0),
+		V4L2_MPEG_VIDEO_H264_LEVEL_5_0,
+		V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		HFI_PROP_LEVEL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LEVEL, ENC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_5,
+		V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		HFI_PROP_LEVEL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LEVEL, DEC, H264,
+		V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) |
+		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2),
+		V4L2_MPEG_VIDEO_H264_LEVEL_6_1,
+		V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		HFI_PROP_LEVEL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LEVEL, DEC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
+		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
+		V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		HFI_PROP_LEVEL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LEVEL, DEC, VP9,
+		V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
+		V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) |
+		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0),
+		V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
+		V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
+		HFI_PROP_LEVEL,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{HEVC_TIER, ENC | DEC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
+		V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
+		BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH),
+		V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
+		V4L2_CID_MPEG_VIDEO_HEVC_TIER,
+		HFI_PROP_TIER,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LF_MODE, ENC, H264,
+		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		DB_H264_DISABLE_SLICE_BOUNDARY,
+		BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
+		BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
+		BIT(DB_H264_DISABLE_SLICE_BOUNDARY),
+		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+		HFI_PROP_DEBLOCKING_MODE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LF_MODE, ENC, HEVC,
+		V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
+		DB_HEVC_DISABLE_SLICE_BOUNDARY,
+		BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) |
+		BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) |
+		BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY),
+		V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED,
+		V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
+		HFI_PROP_DEBLOCKING_MODE,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{LF_ALPHA, ENC, H264,
+		-6, 6, 1, 0,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA},
+
+	{LF_ALPHA, ENC, HEVC,
+		-6, 6, 1, 0,
+		V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2},
+
+	{LF_BETA, ENC, H264,
+		-6, 6, 1, 0,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA},
+
+	{LF_BETA, ENC, HEVC,
+		-6, 6, 1, 0,
+		V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2},
+
+	{SLICE_MODE, ENC, H264 | HEVC,
+		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
+		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) |
+		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES),
+		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		0,
+		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
+
+	{SLICE_MAX_BYTES, ENC, H264 | HEVC,
+		MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE,
+		1, MIN_SLICE_BYTE_SIZE,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+		HFI_PROP_MULTI_SLICE_BYTES_COUNT,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{SLICE_MAX_MB, ENC, H264 | HEVC,
+		1, MAX_SLICE_MB_SIZE, 1, 1,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+		HFI_PROP_MULTI_SLICE_MB_COUNT,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{MB_RC, ENC, H264 | HEVC,
+		0, 1, 1, 1,
+		V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+		0,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{TRANSFORM_8X8, ENC, H264,
+		0, 1, 1, 1,
+		V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+		HFI_PROP_8X8_TRANSFORM,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
+		MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET,
+		1, MAX_CHROMA_QP_OFFSET,
+		V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
+		HFI_PROP_CHROMA_QP_OFFSET,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
+		HFI_PROP_DECODE_ORDER_OUTPUT,
+		CAP_FLAG_INPUT_PORT},
+
+	{DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
+		0, 1, 1, 0,
+		V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
+		HFI_PROP_DECODE_ORDER_OUTPUT,
+		CAP_FLAG_INPUT_PORT},
+
+	{OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
+		0, 1, 1, 0,
+		0,
+		HFI_PROP_DECODE_ORDER_OUTPUT,
+		CAP_FLAG_INPUT_PORT},
+
+	{INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
+		DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
+		1, DEFAULT_MAX_HOST_BUF_COUNT,
+		0,
+		HFI_PROP_BUFFER_HOST_MAX_COUNT,
+		CAP_FLAG_INPUT_PORT},
+
+	{OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
+		DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
+		1, DEFAULT_MAX_HOST_BUF_COUNT,
+		0,
+		HFI_PROP_BUFFER_HOST_MAX_COUNT,
+		CAP_FLAG_OUTPUT_PORT},
+
+	{CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1,
+		DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+		V4L2_CID_MPEG_VIDEO_MUTE_YUV,
+		HFI_PROP_CONCEAL_COLOR_8BIT,
+		CAP_FLAG_INPUT_PORT},
+
+	{CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1,
+		DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+		V4L2_CID_MPEG_VIDEO_MUTE_YUV,
+		HFI_PROP_CONCEAL_COLOR_10BIT,
+		CAP_FLAG_INPUT_PORT},
+
+	{STAGE, DEC | ENC, CODECS_ALL,
+		MSM_VIDC_STAGE_1,
+		MSM_VIDC_STAGE_2, 1,
+		MSM_VIDC_STAGE_2,
+		0,
+		HFI_PROP_STAGE},
+
+	{PIPE, DEC | ENC, CODECS_ALL,
+		MSM_VIDC_PIPE_1,
+		MSM_VIDC_PIPE_4, 1,
+		MSM_VIDC_PIPE_4,
+		0,
+		HFI_PROP_PIPE},
+
+	{POC, DEC, H264, 0, 2, 1, 1,
+		0,
+		HFI_PROP_PIC_ORDER_CNT_TYPE},
+
+	{QUALITY_MODE, ENC, CODECS_ALL,
+		MSM_VIDC_MAX_QUALITY_MODE,
+		MSM_VIDC_POWER_SAVE_MODE, 1,
+		MSM_VIDC_POWER_SAVE_MODE},
+
+	{CODED_FRAMES, DEC, H264 | HEVC,
+		CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE,
+		1, CODED_FRAMES_PROGRESSIVE,
+		0,
+		HFI_PROP_CODED_FRAMES},
+
+	{BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8,
+		0,
+		HFI_PROP_LUMA_CHROMA_BIT_DEPTH},
+
+	{BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0,
+		0},
+
+	{DEFAULT_HEADER, DEC, CODECS_ALL,
+		0, 1, 1, 0,
+		0,
+		HFI_PROP_DEC_DEFAULT_HEADER},
+
+	{RAP_FRAME, DEC, CODECS_ALL,
+		0, 1, 1, 1,
+		0,
+		HFI_PROP_DEC_START_FROM_RAP_FRAME,
+		CAP_FLAG_INPUT_PORT},
+
+	{SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL,
+		0, 1, 1, 1,
+		0,
+		HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME,
+		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
+
+	{ALL_INTRA, ENC, H264 | HEVC,
+		0, 1, 1, 0,
+		0,
+		0,
+		CAP_FLAG_OUTPUT_PORT},
+};
+
+static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_sm8550[] = {
+	/* {cap, domain, codec,
+	 *      children,
+	 *      adjust, set}
+	 */
+
+	{PIX_FMTS, ENC, H264,
+		{IR_PERIOD}},
+
+	{PIX_FMTS, ENC, HEVC,
+		{PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP,
+			B_FRAME_QP, MIN_QUALITY, IR_PERIOD, LTR_COUNT}},
+
+	{PIX_FMTS, DEC, HEVC,
+		{PROFILE}},
+
+	{FRAME_RATE, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_q16},
+
+	{HFLIP, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_flip},
+
+	{VFLIP, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_flip},
+
+	{ROTATION, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_rotation},
+
+	{HEADER_MODE, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_header_mode},
+
+	{WITHOUT_STARTCODE, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_nal_length},
+
+	{REQUEST_I_FRAME, ENC, H264 | HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_req_sync_frame},
+
+	{BIT_RATE, ENC, H264,
+		{PEAK_BITRATE, L0_BR},
+		msm_vidc_adjust_bitrate,
+		msm_vidc_set_bitrate},
+
+	{BIT_RATE, ENC, HEVC,
+		{PEAK_BITRATE, L0_BR},
+		msm_vidc_adjust_bitrate,
+		msm_vidc_set_bitrate},
+
+	{BITRATE_MODE, ENC, H264,
+		{LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
+			B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE,
+			MIN_QUALITY, VBV_DELAY,
+			PEAK_BITRATE, SLICE_MODE},
+		msm_vidc_adjust_bitrate_mode,
+		msm_vidc_set_u32_enum},
+
+	{BITRATE_MODE, ENC, HEVC,
+		{LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
+			B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT,
+			BIT_RATE, MIN_QUALITY, VBV_DELAY,
+			PEAK_BITRATE, SLICE_MODE},
+		msm_vidc_adjust_bitrate_mode,
+		msm_vidc_set_u32_enum},
+
+	{CONSTANT_QUALITY, ENC, HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_constant_quality},
+
+	{GOP_SIZE, ENC, CODECS_ALL,
+		{ALL_INTRA},
+		msm_vidc_adjust_gop_size,
+		msm_vidc_set_gop_size},
+
+	{B_FRAME, ENC, H264 | HEVC,
+		{ALL_INTRA},
+		msm_vidc_adjust_b_frame,
+		msm_vidc_set_u32},
+
+	{LTR_COUNT, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_ltr_count,
+		msm_vidc_set_u32},
+
+	{USE_LTR, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_use_ltr,
+		msm_vidc_set_use_and_mark_ltr},
+
+	{MARK_LTR, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_mark_ltr,
+		msm_vidc_set_use_and_mark_ltr},
+
+	{IR_PERIOD, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_ir_period,
+		msm_vidc_set_ir_period},
+
+	{AU_DELIMITER, ENC, H264 | HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_u32},
+
+	{MIN_QUALITY, ENC, H264,
+		{0},
+		msm_vidc_adjust_min_quality,
+		msm_vidc_set_u32},
+
+	{MIN_QUALITY, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_min_quality,
+		msm_vidc_set_u32},
+
+	{VBV_DELAY, ENC, H264 | HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_cbr_related_properties},
+
+	{PEAK_BITRATE, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_peak_bitrate,
+		msm_vidc_set_cbr_related_properties},
+
+	{MIN_FRAME_QP, ENC, H264,
+		{0},
+		NULL,
+		msm_vidc_set_min_qp},
+
+	{MIN_FRAME_QP, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_hevc_min_qp,
+		msm_vidc_set_min_qp},
+
+	{MAX_FRAME_QP, ENC, H264,
+		{0},
+		NULL,
+		msm_vidc_set_max_qp},
+
+	{MAX_FRAME_QP, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_hevc_max_qp,
+		msm_vidc_set_max_qp},
+
+	{I_FRAME_QP, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_hevc_i_frame_qp,
+		msm_vidc_set_frame_qp},
+
+	{I_FRAME_QP, ENC, H264,
+		{0},
+		NULL,
+		msm_vidc_set_frame_qp},
+
+	{P_FRAME_QP, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_hevc_p_frame_qp,
+		msm_vidc_set_frame_qp},
+
+	{P_FRAME_QP, ENC, H264,
+		{0},
+		NULL,
+		msm_vidc_set_frame_qp},
+
+	{B_FRAME_QP, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_hevc_b_frame_qp,
+		msm_vidc_set_frame_qp},
+
+	{B_FRAME_QP, ENC, H264,
+		{0},
+		NULL,
+		msm_vidc_set_frame_qp},
+
+	{LAYER_TYPE, ENC, H264 | HEVC,
+		{LTR_COUNT}},
+
+	{LAYER_ENABLE, ENC, H264 | HEVC,
+		{0}},
+
+	{ENH_LAYER_COUNT, ENC, H264 | HEVC,
+		{GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE,
+			LTR_COUNT},
+		msm_vidc_adjust_layer_count,
+		msm_vidc_set_layer_count_and_type},
+
+	{L0_BR, ENC, H264 | HEVC,
+		{L1_BR},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{L1_BR, ENC, H264 | HEVC,
+		{L2_BR},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{L2_BR, ENC, H264 | HEVC,
+		{L3_BR},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{L3_BR, ENC, H264 | HEVC,
+		{L4_BR},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{L4_BR, ENC, H264 | HEVC,
+		{L5_BR},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{L5_BR, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_layer_bitrate,
+		msm_vidc_set_layer_bitrate},
+
+	{ENTROPY_MODE, ENC, H264,
+		{BIT_RATE},
+		msm_vidc_adjust_entropy_mode,
+		msm_vidc_set_u32},
+
+	{PROFILE, ENC, H264,
+		{ENTROPY_MODE, TRANSFORM_8X8},
+		NULL,
+		msm_vidc_set_u32_enum},
+
+	{PROFILE, DEC, H264,
+		{ENTROPY_MODE},
+		NULL,
+		msm_vidc_set_u32_enum},
+
+	{PROFILE, ENC | DEC, HEVC,
+		{0},
+		msm_vidc_adjust_profile,
+		msm_vidc_set_u32_enum},
+
+	{PROFILE, DEC, VP9,
+		{0},
+		NULL,
+		msm_vidc_set_u32_enum},
+
+	{LEVEL, DEC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_u32_enum},
+
+	{LEVEL, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_level},
+
+	{HEVC_TIER, ENC | DEC, HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_u32_enum},
+
+	{LF_MODE, ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_deblock_mode},
+
+	{SLICE_MODE, ENC, H264 | HEVC,
+		{STAGE},
+		msm_vidc_adjust_slice_count,
+		msm_vidc_set_slice_count},
+
+	{TRANSFORM_8X8, ENC, H264,
+		{0},
+		msm_vidc_adjust_transform_8x8,
+		msm_vidc_set_u32},
+
+	{CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
+		{0},
+		msm_vidc_adjust_chroma_qp_index_offset,
+		msm_vidc_set_chroma_qp_index_offset},
+
+	{DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
+		{OUTPUT_ORDER},
+		NULL,
+		NULL},
+
+	{DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
+		{OUTPUT_ORDER},
+		NULL,
+		NULL},
+
+	{OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
+		{0},
+		msm_vidc_adjust_output_order,
+		msm_vidc_set_u32},
+
+	{INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
+		{0},
+		msm_vidc_adjust_input_buf_host_max_count,
+		msm_vidc_set_u32},
+
+	{INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_input_buf_host_max_count,
+		msm_vidc_set_u32},
+
+	{OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
+		{0},
+		msm_vidc_adjust_output_buf_host_max_count,
+		msm_vidc_set_u32},
+
+	{OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
+		{0},
+		msm_vidc_adjust_output_buf_host_max_count,
+		msm_vidc_set_u32},
+
+	{CONCEAL_COLOR_8BIT, DEC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_u32_packed},
+
+	{CONCEAL_COLOR_10BIT, DEC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_u32_packed},
+
+	{STAGE, ENC | DEC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_stage},
+
+	{STAGE, ENC, H264 | HEVC,
+		{0},
+		NULL,
+		msm_vidc_set_stage},
+
+	{STAGE, DEC, H264 | HEVC | VP9,
+		{0},
+		NULL,
+		msm_vidc_set_stage},
+
+	{PIPE, DEC | ENC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_pipe},
+
+	{RAP_FRAME, DEC, CODECS_ALL,
+		{0},
+		NULL,
+		msm_vidc_set_u32},
+
+	{ALL_INTRA, ENC, H264 | HEVC,
+		{LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE},
+		msm_vidc_adjust_all_intra,
+		NULL},
+};
+
+/* Default UBWC config for LPDDR5 */
+static struct msm_vidc_ubwc_config_data ubwc_config_sm8550[] = {
+	UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1),
+};
+
+static struct msm_vidc_format_capability format_data_sm8550 = {
+	.codec_info = codec_data_sm8550,
+	.codec_info_size = ARRAY_SIZE(codec_data_sm8550),
+	.color_format_info = color_format_data_sm8550,
+	.color_format_info_size = ARRAY_SIZE(color_format_data_sm8550),
+	.color_prim_info = color_primaries_data_sm8550,
+	.color_prim_info_size = ARRAY_SIZE(color_primaries_data_sm8550),
+	.transfer_char_info = transfer_char_data_sm8550,
+	.transfer_char_info_size = ARRAY_SIZE(transfer_char_data_sm8550),
+	.matrix_coeff_info = matrix_coeff_data_sm8550,
+	.matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_sm8550),
+};
+
+/* name, min_kbps, max_kbps */
+static const struct bw_table sm8550_bw_table[] = {
+	{ "venus-cnoc",  1000, 1000     },
+	{ "venus-ddr",   1000, 15000000 },
+};
+
+/* name */
+static const struct pd_table sm8550_pd_table[] = {
+	{ "iris-ctl" },
+	{ "vcodec"   },
+};
+
+/* name */
+static const char * const sm8550_opp_table[] = { "mx", "mmcx", NULL };
+
+/* name, clock id, scaling */
+static const struct clk_table sm8550_clk_table[] = {
+	{ "gcc_video_axi0",         GCC_VIDEO_AXI0_CLK,     0 },
+	{ "core_clk",               VIDEO_CC_MVS0C_CLK,     0 },
+	{ "vcodec_clk",             VIDEO_CC_MVS0_CLK,      1 },
+};
+
+/* name, exclusive_release */
+static const struct clk_rst_table sm8550_clk_reset_table[] = {
+	{ "video_axi_reset",        0  },
+};
+
+/* name, start, size, secure, dma_coherant, region, dma_mask */
+const struct context_bank_table sm8550_context_bank_table[] = {
+	{"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0xe0000000 - 1},
+	{"qcom,vidc,cb-sec-non-pxl",   0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL,  0 },
+};
+
+/* freq */
+static struct freq_table sm8550_freq_table[] = {
+	{533333333}, {444000000}, {366000000}, {338000000}, {240000000}
+};
+
+/* register, value, mask */
+static const struct reg_preset_table sm8550_reg_preset_table[] = {
+	{ 0xB0088, 0x0, 0x11 },
+};
+
+/* decoder properties */
+static const u32 sm8550_vdec_psc_avc[] = {
+	HFI_PROP_BITSTREAM_RESOLUTION,
+	HFI_PROP_CROP_OFFSETS,
+	HFI_PROP_CODED_FRAMES,
+	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+	HFI_PROP_PIC_ORDER_CNT_TYPE,
+	HFI_PROP_PROFILE,
+	HFI_PROP_LEVEL,
+	HFI_PROP_SIGNAL_COLOR_INFO,
+};
+
+static const u32 sm8550_vdec_psc_hevc[] = {
+	HFI_PROP_BITSTREAM_RESOLUTION,
+	HFI_PROP_CROP_OFFSETS,
+	HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+	HFI_PROP_PROFILE,
+	HFI_PROP_LEVEL,
+	HFI_PROP_TIER,
+	HFI_PROP_SIGNAL_COLOR_INFO,
+};
+
+static const u32 sm8550_vdec_psc_vp9[] = {
+	HFI_PROP_BITSTREAM_RESOLUTION,
+	HFI_PROP_CROP_OFFSETS,
+	HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+	HFI_PROP_PROFILE,
+	HFI_PROP_LEVEL,
+};
+
+static const u32 sm8550_vdec_input_properties_avc[] = {
+	HFI_PROP_NO_OUTPUT,
+	HFI_PROP_SUBFRAME_INPUT,
+};
+
+static const u32 sm8550_vdec_input_properties_hevc[] = {
+	HFI_PROP_NO_OUTPUT,
+	HFI_PROP_SUBFRAME_INPUT,
+};
+
+static const u32 sm8550_vdec_input_properties_vp9[] = {
+	HFI_PROP_NO_OUTPUT,
+	HFI_PROP_SUBFRAME_INPUT,
+};
+
+static const u32 sm8550_vdec_output_properties_avc[] = {
+	HFI_PROP_WORST_COMPRESSION_RATIO,
+	HFI_PROP_WORST_COMPLEXITY_FACTOR,
+	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_DPB_LIST,
+	HFI_PROP_CABAC_SESSION,
+};
+
+static const u32 sm8550_vdec_output_properties_hevc[] = {
+	HFI_PROP_WORST_COMPRESSION_RATIO,
+	HFI_PROP_WORST_COMPLEXITY_FACTOR,
+	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_DPB_LIST,
+};
+
+static const u32 sm8550_vdec_output_properties_vp9[] = {
+	HFI_PROP_WORST_COMPRESSION_RATIO,
+	HFI_PROP_WORST_COMPLEXITY_FACTOR,
+	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_DPB_LIST,
+};
+
+static const struct msm_vidc_platform_data sm8550_data = {
+	/* resources dependent on other module */
+	.bw_tbl = sm8550_bw_table,
+	.bw_tbl_size = ARRAY_SIZE(sm8550_bw_table),
+	.clk_tbl = sm8550_clk_table,
+	.clk_tbl_size = ARRAY_SIZE(sm8550_clk_table),
+	.clk_rst_tbl = sm8550_clk_reset_table,
+	.clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table),
+	.subcache_tbl = NULL,
+	.subcache_tbl_size = 0,
+
+	/* populate context bank */
+	.context_bank_tbl = sm8550_context_bank_table,
+	.context_bank_tbl_size = ARRAY_SIZE(sm8550_context_bank_table),
+
+	/* populate power domain and opp table */
+	.pd_tbl = sm8550_pd_table,
+	.pd_tbl_size = ARRAY_SIZE(sm8550_pd_table),
+	.opp_tbl = sm8550_opp_table,
+	.opp_tbl_size = ARRAY_SIZE(sm8550_opp_table),
+
+	/* platform specific resources */
+	.freq_tbl = sm8550_freq_table,
+	.freq_tbl_size = ARRAY_SIZE(sm8550_freq_table),
+	.reg_prst_tbl = sm8550_reg_preset_table,
+	.reg_prst_tbl_size = ARRAY_SIZE(sm8550_reg_preset_table),
+	.fwname = "vpu30_4v",
+	.pas_id = 9,
+
+	/* caps related resorces */
+	.core_data = core_data_sm8550,
+	.core_data_size = ARRAY_SIZE(core_data_sm8550),
+	.inst_cap_data = instance_cap_data_sm8550,
+	.inst_cap_data_size = ARRAY_SIZE(instance_cap_data_sm8550),
+	.inst_cap_dependency_data = instance_cap_dependency_data_sm8550,
+	.inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_sm8550),
+	.ubwc_config = ubwc_config_sm8550,
+	.format_data = &format_data_sm8550,
+
+	/* decoder properties related*/
+	.psc_avc_tbl = sm8550_vdec_psc_avc,
+	.psc_avc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_avc),
+	.psc_hevc_tbl = sm8550_vdec_psc_hevc,
+	.psc_hevc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_hevc),
+	.psc_vp9_tbl = sm8550_vdec_psc_vp9,
+	.psc_vp9_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_vp9),
+	.dec_input_prop_avc = sm8550_vdec_input_properties_avc,
+	.dec_input_prop_hevc = sm8550_vdec_input_properties_hevc,
+	.dec_input_prop_vp9 = sm8550_vdec_input_properties_vp9,
+	.dec_input_prop_size_avc = ARRAY_SIZE(sm8550_vdec_input_properties_avc),
+	.dec_input_prop_size_hevc = ARRAY_SIZE(sm8550_vdec_input_properties_hevc),
+	.dec_input_prop_size_vp9 = ARRAY_SIZE(sm8550_vdec_input_properties_vp9),
+	.dec_output_prop_avc = sm8550_vdec_output_properties_avc,
+	.dec_output_prop_hevc = sm8550_vdec_output_properties_hevc,
+	.dec_output_prop_vp9 = sm8550_vdec_output_properties_vp9,
+	.dec_output_prop_size_avc = ARRAY_SIZE(sm8550_vdec_output_properties_avc),
+	.dec_output_prop_size_hevc = ARRAY_SIZE(sm8550_vdec_output_properties_hevc),
+	.dec_output_prop_size_vp9 = ARRAY_SIZE(sm8550_vdec_output_properties_vp9),
+};
+
+static int msm_vidc_init_data(struct msm_vidc_core *core)
+{
+	d_vpr_h("%s: initialize sm8550 data\n", __func__);
+
+	core->platform->data = sm8550_data;
+
+	return 0;
+}
+
+int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core)
+{
+	return msm_vidc_init_data(core);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 27/33] iris: variant: add helper functions for register handling
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (25 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550 Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 28/33] iris: variant: iris3: add iris3 specific ops Vikash Garodia
                   ` (8 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements the functions to read and write different regsiters.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/variant/common/inc/msm_vidc_variant.h     |  22 +++
 .../iris/variant/common/src/msm_vidc_variant.c     | 163 +++++++++++++++++++++
 2 files changed, 185 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c

diff --git a/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h b/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
new file mode 100644
index 0000000..58ba276
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_VARIANT_H_
+#define _MSM_VIDC_VARIANT_H_
+
+#include <linux/types.h>
+
+struct msm_vidc_core;
+
+int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
+			    u32 mask);
+int __write_register(struct msm_vidc_core *core, u32 reg, u32 value);
+int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value);
+int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
+				      u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us);
+int __set_registers(struct msm_vidc_core *core);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c b/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
new file mode 100644
index 0000000..4901844
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/iopoll.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_state.h"
+#include "msm_vidc_variant.h"
+#include "venus_hfi.h"
+
+int __write_register(struct msm_vidc_core *core, u32 reg, u32 value)
+{
+	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("HFI Write register failed : Power is OFF\n");
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+	d_vpr_l("regwrite(%pK + %#x) = %#x\n", base_addr, hwiosymaddr, value);
+	base_addr += hwiosymaddr;
+	writel_relaxed(value, base_addr);
+
+	/* Memory barrier to make sure value is written into the register */
+	wmb();
+
+	return rc;
+}
+
+/*
+ * Argument mask is used to specify which bits to update. In case mask is 0x11,
+ * only bits 0 & 4 will be updated with corresponding bits from value. To update
+ * entire register with value, set mask = 0xFFFFFFFF.
+ */
+int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
+			    u32 mask)
+{
+	u32 prev_val, new_val;
+	u8 *base_addr;
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("%s: register write failed, power is off\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+	base_addr += reg;
+
+	prev_val = readl_relaxed(base_addr);
+	/*
+	 * Memory barrier to ensure register read is correct
+	 */
+	rmb();
+
+	new_val = (prev_val & ~mask) | (value & mask);
+	d_vpr_l("Base addr: %pK, writing to: %#x, mask: %#x\n",
+		base_addr, reg, mask);
+
+	d_vpr_l("previous-value: %#x, value: %#x, new-value: %#x...\n",
+		prev_val, value, new_val);
+	writel_relaxed(new_val, base_addr);
+	/*
+	 * Memory barrier to make sure value is written into the register.
+	 */
+	wmb();
+
+	return rc;
+}
+
+int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value)
+{
+	int rc = 0;
+	u8 *base_addr;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("HFI Read register failed : Power is OFF\n");
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+
+	*value = readl_relaxed(base_addr + reg);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	d_vpr_l("regread(%pK + %#x) = %#x\n", base_addr, reg, *value);
+
+	return rc;
+}
+
+int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
+				      u32 mask, u32 exp_val, u32 sleep_us,
+				      u32 timeout_us)
+{
+	int rc = 0;
+	u32 val = 0;
+	u8 *addr;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("%s failed: Power is OFF\n", __func__);
+		return -EINVAL;
+	}
+
+	addr = (u8 *)core->resource->register_base_addr + reg;
+
+	rc = readl_relaxed_poll_timeout(addr, val, ((val & mask) == exp_val), sleep_us, timeout_us);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	d_vpr_l("regread(%pK + %#x) = %#x. rc %d, mask %#x, exp_val %#x\n",
+		core->resource->register_base_addr, reg, val, rc, mask, exp_val);
+	d_vpr_l("cond %u, sleep %u, timeout %u\n",
+		((val & mask) == exp_val), sleep_us, timeout_us);
+
+	return rc;
+}
+
+int __set_registers(struct msm_vidc_core *core)
+{
+	const struct reg_preset_table *reg_prst;
+	unsigned int prst_count;
+	int cnt, rc = 0;
+
+	reg_prst = core->platform->data.reg_prst_tbl;
+	prst_count = core->platform->data.reg_prst_tbl_size;
+
+	/* skip if there is no preset reg available */
+	if (!reg_prst || !prst_count)
+		return 0;
+
+	for (cnt = 0; cnt < prst_count; cnt++) {
+		rc = __write_register_masked(core, reg_prst[cnt].reg,
+					     reg_prst[cnt].value, reg_prst[cnt].mask);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 28/33] iris: variant: iris3: add iris3 specific ops
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (26 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 27/33] iris: variant: add helper functions for register handling Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations Vikash Garodia
                   ` (7 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements iris3 specific ops for power on, power off,
boot firmware, power collapse etc.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../qcom/iris/variant/iris3/inc/msm_vidc_iris3.h   |  15 +
 .../qcom/iris/variant/iris3/src/msm_vidc_iris3.c   | 954 +++++++++++++++++++++
 2 files changed, 969 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c

diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
new file mode 100644
index 0000000..704367e
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_IRIS3_H_
+#define _MSM_VIDC_IRIS3_H_
+
+#include "msm_vidc_core.h"
+
+int msm_vidc_init_iris3(struct msm_vidc_core *core);
+int msm_vidc_adjust_bitrate_boost_iris3(void *instance, struct v4l2_ctrl *ctrl);
+
+#endif // _MSM_VIDC_IRIS3_H_
diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
new file mode 100644
index 0000000..95dff62
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_buffer.h"
+#include "msm_vidc_buffer_iris3.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_iris3.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_power_iris3.h"
+#include "msm_vidc_state.h"
+#include "msm_vidc_variant.h"
+#include "venus_hfi.h"
+
+#define VIDEO_ARCH_LX 1
+
+#define VCODEC_BASE_OFFS_IRIS3                 0x00000000
+#define AON_MVP_NOC_RESET                      0x0001F000
+#define CPU_BASE_OFFS_IRIS3                    0x000A0000
+#define AON_BASE_OFFS			               0x000E0000
+#define CPU_CS_BASE_OFFS_IRIS3		           (CPU_BASE_OFFS_IRIS3)
+#define CPU_IC_BASE_OFFS_IRIS3		           (CPU_BASE_OFFS_IRIS3)
+
+#define CPU_CS_A2HSOFTINTCLR_IRIS3             (CPU_CS_BASE_OFFS_IRIS3 + 0x1C)
+#define CPU_CS_VCICMD_IRIS3                    (CPU_CS_BASE_OFFS_IRIS3 + 0x20)
+#define CPU_CS_VCICMDARG0_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x24)
+#define CPU_CS_VCICMDARG1_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x28)
+#define CPU_CS_VCICMDARG2_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x2C)
+#define CPU_CS_VCICMDARG3_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x30)
+#define CPU_CS_VMIMSG_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x34)
+#define CPU_CS_VMIMSGAG0_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x38)
+#define CPU_CS_VMIMSGAG1_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x3C)
+#define CPU_CS_SCIACMD_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x48)
+#define CPU_CS_H2XSOFTINTEN_IRIS3	(CPU_CS_BASE_OFFS_IRIS3 + 0x148)
+
+/* HFI_CTRL_STATUS */
+#define CPU_CS_SCIACMDARG0_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x4C)
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3	0xfe
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS3           0x100
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3     0x40000000
+
+/* HFI_QTBL_INFO */
+#define CPU_CS_SCIACMDARG1_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define CPU_CS_SCIACMDARG2_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x54)
+
+/* HFI_VERSION_INFO */
+#define CPU_CS_SCIACMDARG3_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x58)
+
+/* SFR_ADDR */
+#define CPU_CS_SCIBCMD_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x5C)
+
+/* MMAP_ADDR */
+#define CPU_CS_SCIBCMDARG0_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x60)
+
+/* UC_REGION_ADDR */
+#define CPU_CS_SCIBARG1_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x64)
+
+/* UC_REGION_ADDR */
+#define CPU_CS_SCIBARG2_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x68)
+
+#define CPU_CS_AHB_BRIDGE_SYNC_RESET            (CPU_CS_BASE_OFFS_IRIS3 + 0x160)
+#define CPU_CS_AHB_BRIDGE_SYNC_RESET_STATUS     (CPU_CS_BASE_OFFS_IRIS3 + 0x164)
+
+/* FAL10 Feature Control */
+#define CPU_CS_X2RPMH_IRIS3		(CPU_CS_BASE_OFFS_IRIS3 + 0x168)
+#define CPU_CS_X2RPMH_MASK0_BMSK_IRIS3	0x1
+#define CPU_CS_X2RPMH_MASK0_SHFT_IRIS3	0x0
+#define CPU_CS_X2RPMH_MASK1_BMSK_IRIS3	0x2
+#define CPU_CS_X2RPMH_MASK1_SHFT_IRIS3	0x1
+#define CPU_CS_X2RPMH_SWOVERRIDE_BMSK_IRIS3	0x4
+#define CPU_CS_X2RPMH_SWOVERRIDE_SHFT_IRIS3	0x3
+
+#define CPU_IC_SOFTINT_IRIS3		(CPU_IC_BASE_OFFS_IRIS3 + 0x150)
+#define CPU_IC_SOFTINT_H2A_SHFT_IRIS3	0x0
+
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: AON_MVP_NOC_RESET_REGISTERS
+ * --------------------------------------------------------------------------
+ */
+#define AON_WRAPPER_MVP_NOC_RESET_REQ   (AON_MVP_NOC_RESET + 0x000)
+#define AON_WRAPPER_MVP_NOC_RESET_ACK   (AON_MVP_NOC_RESET + 0x004)
+
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: wrapper
+ * --------------------------------------------------------------------------
+ */
+#define WRAPPER_BASE_OFFS_IRIS3		0x000B0000
+#define WRAPPER_INTR_STATUS_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x0C)
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3	0x8
+#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3	0x4
+
+#define WRAPPER_INTR_MASK_IRIS3		(WRAPPER_BASE_OFFS_IRIS3 + 0x10)
+#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS3	0x8
+#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS3	0x4
+
+#define WRAPPER_CPU_CLOCK_CONFIG_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x2000)
+#define WRAPPER_CPU_CGC_DIS_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x2010)
+#define WRAPPER_CPU_STATUS_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x2014)
+
+#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x54)
+#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS3	(WRAPPER_BASE_OFFS_IRIS3 + 0x58)
+#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL	(WRAPPER_BASE_OFFS_IRIS3 + 0x5C)
+#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS		(WRAPPER_BASE_OFFS_IRIS3 + 0x60)
+#define WRAPPER_CORE_POWER_STATUS		(WRAPPER_BASE_OFFS_IRIS3 + 0x80)
+#define WRAPPER_CORE_CLOCK_CONFIG_IRIS3		(WRAPPER_BASE_OFFS_IRIS3 + 0x88)
+
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: tz_wrapper
+ * --------------------------------------------------------------------------
+ */
+#define WRAPPER_TZ_BASE_OFFS	0x000C0000
+#define WRAPPER_TZ_CPU_CLOCK_CONFIG	(WRAPPER_TZ_BASE_OFFS)
+#define WRAPPER_TZ_CPU_STATUS	(WRAPPER_TZ_BASE_OFFS + 0x10)
+#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG	(WRAPPER_TZ_BASE_OFFS + 0x14)
+#define WRAPPER_TZ_QNS4PDXFIFO_RESET	(WRAPPER_TZ_BASE_OFFS + 0x18)
+
+#define CTRL_INIT_IRIS3		CPU_CS_SCIACMD_IRIS3
+
+#define CTRL_STATUS_IRIS3	CPU_CS_SCIACMDARG0_IRIS3
+#define CTRL_ERROR_STATUS__M_IRIS3 \
+		CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3
+#define CTRL_INIT_IDLE_MSG_BMSK_IRIS3 \
+		CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3
+#define CTRL_STATUS_PC_READY_IRIS3 \
+		CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS3
+
+#define QTBL_INFO_IRIS3		CPU_CS_SCIACMDARG1_IRIS3
+
+#define QTBL_ADDR_IRIS3		CPU_CS_SCIACMDARG2_IRIS3
+
+#define VERSION_INFO_IRIS3	    CPU_CS_SCIACMDARG3_IRIS3
+
+#define SFR_ADDR_IRIS3		    CPU_CS_SCIBCMD_IRIS3
+#define MMAP_ADDR_IRIS3		CPU_CS_SCIBCMDARG0_IRIS3
+#define UC_REGION_ADDR_IRIS3	CPU_CS_SCIBARG1_IRIS3
+#define UC_REGION_SIZE_IRIS3	CPU_CS_SCIBARG2_IRIS3
+
+#define AON_WRAPPER_MVP_NOC_LPI_CONTROL	(AON_BASE_OFFS)
+#define AON_WRAPPER_MVP_NOC_LPI_STATUS	(AON_BASE_OFFS + 0x4)
+
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: VCODEC_SS registers
+ * --------------------------------------------------------------------------
+ */
+#define VCODEC_SS_IDLE_STATUSN           (VCODEC_BASE_OFFS_IRIS3 + 0x70)
+
+/*
+ * --------------------------------------------------------------------------
+ * MODULE: vcodec noc error log registers (iris3)
+ * --------------------------------------------------------------------------
+ */
+#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS		0x00010000
+#define VCODEC_NOC_ERL_MAIN_SWID_LOW			0x00011200
+#define VCODEC_NOC_ERL_MAIN_SWID_HIGH			0x00011204
+#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW			0x00011208
+#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW			0x00011210
+#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW			0x00011218
+#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW			0x00011220
+#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH		0x00011224
+#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW			0x00011228
+#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH		0x0001122C
+#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW			0x00011230
+#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH		0x00011234
+#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW			0x00011238
+#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH		0x0001123C
+
+static int __interrupt_init_iris3(struct msm_vidc_core *core)
+{
+	u32 mask_val = 0;
+	int rc = 0;
+
+	/* All interrupts should be disabled initially 0x1F6 : Reset value */
+	rc = __read_register(core, WRAPPER_INTR_MASK_IRIS3, &mask_val);
+	if (rc)
+		return rc;
+
+	/* Write 0 to unmask CPU and WD interrupts */
+	mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS3 |
+			WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS3);
+	rc = __write_register(core, WRAPPER_INTR_MASK_IRIS3, mask_val);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int __setup_ucregion_memory_map_iris3(struct msm_vidc_core *core)
+{
+	u32 value;
+	int rc = 0;
+
+	value = (u32)core->iface_q_table.align_device_addr;
+	rc = __write_register(core, UC_REGION_ADDR_IRIS3, value);
+	if (rc)
+		return rc;
+
+	value = SHARED_QSIZE;
+	rc = __write_register(core, UC_REGION_SIZE_IRIS3, value);
+	if (rc)
+		return rc;
+
+	value = (u32)core->iface_q_table.align_device_addr;
+	rc = __write_register(core, QTBL_ADDR_IRIS3, value);
+	if (rc)
+		return rc;
+
+	rc = __write_register(core, QTBL_INFO_IRIS3, 0x01);
+	if (rc)
+		return rc;
+
+	/* update queues vaddr for debug purpose */
+	value = (u32)((u64)core->iface_q_table.align_virtual_addr);
+	rc = __write_register(core, CPU_CS_VCICMDARG0_IRIS3, value);
+	if (rc)
+		return rc;
+
+	value = (u32)((u64)core->iface_q_table.align_virtual_addr >> 32);
+	rc = __write_register(core, CPU_CS_VCICMDARG1_IRIS3, value);
+	if (rc)
+		return rc;
+
+	if (core->sfr.align_device_addr) {
+		value = (u32)core->sfr.align_device_addr + VIDEO_ARCH_LX;
+		rc = __write_register(core, SFR_ADDR_IRIS3, value);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static bool is_iris3_hw_power_collapsed(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u32 value = 0, pwr_status = 0;
+
+	rc = __read_register(core, WRAPPER_CORE_POWER_STATUS, &value);
+	if (rc)
+		return false;
+
+	/* if BIT(1) is 1 then video hw power is on else off */
+	pwr_status = value & BIT(1);
+	return pwr_status ? false : true;
+}
+
+static int __power_off_iris3_hardware(struct msm_vidc_core *core)
+{
+	int rc = 0, i;
+	u32 value = 0;
+	bool pwr_collapsed = false;
+
+	/*
+	 * Incase hw power control is enabled, for both CPU WD, video
+	 * hw unresponsive cases, check for power status to decide on
+	 * executing NOC reset sequence before disabling power. If there
+	 * is no CPU WD and hw power control is enabled, fw is expected
+	 * to power collapse video hw always.
+	 */
+	if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) {
+		pwr_collapsed = is_iris3_hw_power_collapsed(core);
+		if (is_core_sub_state(core, CORE_SUBSTATE_CPU_WATCHDOG) ||
+		    is_core_sub_state(core, CORE_SUBSTATE_VIDEO_UNRESPONSIVE)) {
+			if (pwr_collapsed) {
+				d_vpr_e("%s: video hw power collapsed %s\n",
+					__func__, core->sub_state_name);
+				goto disable_power;
+			} else {
+				d_vpr_e("%s: video hw is power ON %s\n",
+					__func__, core->sub_state_name);
+			}
+		} else {
+			if (!pwr_collapsed)
+				d_vpr_e("%s: video hw is not power collapsed\n", __func__);
+
+			d_vpr_h("%s: disabling hw power\n", __func__);
+			goto disable_power;
+		}
+	}
+
+	/*
+	 * check to make sure core clock branch enabled else
+	 * we cannot read vcodec top idle register
+	 */
+	rc = __read_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS3, &value);
+	if (rc)
+		return rc;
+
+	if (value) {
+		d_vpr_h("%s: core clock config not enabled, enabling it to read vcodec registers\n",
+			__func__);
+		rc = __write_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS3, 0);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * add MNoC idle check before collapsing MVS0 per HPG update
+	 * poll for NoC DMA idle -> HPG 6.1.1
+	 */
+	for (i = 0; i < core->capabilities[NUM_VPP_PIPE].value; i++) {
+		rc = __read_register_with_poll_timeout(core, VCODEC_SS_IDLE_STATUSN + 4 * i,
+						       0x400000, 0x400000, 2000, 20000);
+		if (rc)
+			d_vpr_h("%s: VCODEC_SS_IDLE_STATUSN (%d) is not idle (%#x)\n",
+				__func__, i, value);
+	}
+
+	/* Apply partial reset on MSF interface and wait for ACK */
+	rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x3);
+	if (rc)
+		return rc;
+
+	rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK,
+					       0x3, 0x3, 200, 2000);
+	if (rc)
+		d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET assert failed\n", __func__);
+
+	/* De-assert partial reset on MSF interface and wait for ACK */
+	rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x0);
+	if (rc)
+		return rc;
+
+	rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK,
+					       0x3, 0x0, 200, 2000);
+	if (rc)
+		d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET de-assert failed\n", __func__);
+
+	/*
+	 * Reset both sides of 2 ahb2ahb_bridges (TZ and non-TZ)
+	 * do we need to check status register here?
+	 */
+	rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x3);
+	if (rc)
+		return rc;
+	rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x2);
+	if (rc)
+		return rc;
+	rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x0);
+	if (rc)
+		return rc;
+
+disable_power:
+	/* power down process */
+	rc = call_res_op(core, gdsc_off, core, "vcodec");
+	if (rc) {
+		d_vpr_e("%s: disable regulator vcodec failed\n", __func__);
+		rc = 0;
+	}
+
+	rc = call_res_op(core, clk_disable, core, "vcodec_clk");
+	if (rc) {
+		d_vpr_e("%s: disable unprepare vcodec_clk failed\n", __func__);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static int __power_off_iris3_controller(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	/*
+	 * mask fal10_veto QLPAC error since fal10_veto can go 1
+	 * when pwwait == 0 and clamped to 0 -> HPG 6.1.2
+	 */
+	rc = __write_register(core, CPU_CS_X2RPMH_IRIS3, 0x3);
+	if (rc)
+		return rc;
+
+	/* set MNoC to low power, set PD_NOC_QREQ (bit 0) */
+	rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL,
+				     0x1, BIT(0));
+	if (rc)
+		return rc;
+
+	rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_LPI_STATUS,
+					       0x1, 0x1, 200, 2000);
+	if (rc)
+		d_vpr_h("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__);
+
+	/* Set Iris CPU NoC to Low power */
+	rc = __write_register_masked(core, WRAPPER_IRIS_CPU_NOC_LPI_CONTROL,
+				     0x1, BIT(0));
+	if (rc)
+		return rc;
+
+	rc = __read_register_with_poll_timeout(core, WRAPPER_IRIS_CPU_NOC_LPI_STATUS,
+					       0x1, 0x1, 200, 2000);
+	if (rc)
+		d_vpr_h("%s: WRAPPER_IRIS_CPU_NOC_LPI_CONTROL failed\n", __func__);
+
+	/* Debug bridge LPI release */
+	rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS3, 0x0);
+	if (rc)
+		return rc;
+
+	rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS3,
+					       0xffffffff, 0x0, 200, 2000);
+	if (rc)
+		d_vpr_h("%s: debug bridge release failed\n", __func__);
+
+	/* Reset MVP QNS4PDXFIFO */
+	rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x3);
+	if (rc)
+		return rc;
+
+	rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x1);
+	if (rc)
+		return rc;
+
+	rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x0);
+	if (rc)
+		return rc;
+
+	rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x0);
+	if (rc)
+		return rc;
+
+	/* Turn off MVP MVS0C core clock */
+	rc = call_res_op(core, clk_disable, core, "core_clk");
+	if (rc) {
+		d_vpr_e("%s: disable unprepare core_clk failed\n", __func__);
+		rc = 0;
+	}
+
+	/* power down process */
+	rc = call_res_op(core, gdsc_off, core, "iris-ctl");
+	if (rc) {
+		d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static int __power_off_iris3(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
+		return 0;
+
+	rc = call_res_op(core, set_clks, core, 0);
+	if (rc)
+		d_vpr_e("%s: resetting clocks failed\n", __func__);
+
+	if (__power_off_iris3_hardware(core))
+		d_vpr_e("%s: failed to power off hardware\n", __func__);
+
+	if (__power_off_iris3_controller(core))
+		d_vpr_e("%s: failed to power off controller\n", __func__);
+
+	rc = call_res_op(core, set_bw, core, 0, 0);
+	if (rc)
+		d_vpr_e("%s: failed to unvote buses\n", __func__);
+
+	if (!call_iris_op(core, watchdog, core, core->intr_status))
+		disable_irq_nosync(core->resource->irq);
+
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
+
+	return rc;
+}
+
+static int __power_on_iris3_controller(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = call_res_op(core, gdsc_on, core, "iris-ctl");
+	if (rc)
+		goto fail_regulator;
+
+	rc = call_res_op(core, reset_bridge, core);
+	if (rc)
+		goto fail_reset_ahb2axi;
+
+	rc = call_res_op(core, clk_enable, core, "gcc_video_axi0");
+	if (rc)
+		goto fail_clk_axi;
+
+	rc = call_res_op(core, clk_enable, core, "core_clk");
+	if (rc)
+		goto fail_clk_controller;
+
+	return 0;
+
+fail_clk_controller:
+	call_res_op(core, clk_disable, core, "gcc_video_axi0");
+fail_clk_axi:
+fail_reset_ahb2axi:
+	call_res_op(core, gdsc_off, core, "iris-ctl");
+fail_regulator:
+	return rc;
+}
+
+static int __power_on_iris3_hardware(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = call_res_op(core, gdsc_on, core, "vcodec");
+	if (rc)
+		goto fail_regulator;
+
+	rc = call_res_op(core, clk_enable, core, "vcodec_clk");
+	if (rc)
+		goto fail_clk_controller;
+
+	return 0;
+
+fail_clk_controller:
+	call_res_op(core, gdsc_off, core, "vcodec");
+fail_regulator:
+	return rc;
+}
+
+static int __power_on_iris3(struct msm_vidc_core *core)
+{
+	struct frequency_table *freq_tbl;
+	u32 freq = 0;
+	int rc = 0;
+
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
+		return 0;
+
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return -EINVAL;
+	}
+
+	/* Vote for all hardware resources */
+	rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
+	if (rc) {
+		d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc);
+		goto fail_vote_buses;
+	}
+
+	rc = __power_on_iris3_controller(core);
+	if (rc) {
+		d_vpr_e("%s: failed to power on iris3 controller\n", __func__);
+		goto fail_power_on_controller;
+	}
+
+	rc = __power_on_iris3_hardware(core);
+	if (rc) {
+		d_vpr_e("%s: failed to power on iris3 hardware\n", __func__);
+		goto fail_power_on_hardware;
+	}
+	/* video controller and hardware powered on successfully */
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+	if (rc)
+		goto fail_power_on_substate;
+
+	freq_tbl = core->resource->freq_set.freq_tbl;
+	freq = core->power.clk_freq ? core->power.clk_freq :
+				      freq_tbl[0].freq;
+
+	rc = call_res_op(core, set_clks, core, freq);
+	if (rc) {
+		d_vpr_e("%s: failed to scale clocks\n", __func__);
+		rc = 0;
+	}
+	/*
+	 * Re-program all of the registers that get reset as a result of
+	 * regulator_disable() and _enable()
+	 */
+	__set_registers(core);
+
+	__interrupt_init_iris3(core);
+	core->intr_status = 0;
+	enable_irq(core->resource->irq);
+
+	return rc;
+
+fail_power_on_substate:
+	__power_off_iris3_hardware(core);
+fail_power_on_hardware:
+	__power_off_iris3_controller(core);
+fail_power_on_controller:
+	call_res_op(core, set_bw, core, 0, 0);
+fail_vote_buses:
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
+	return rc;
+}
+
+static int __prepare_pc_iris3(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
+	u32 ctrl_status = 0;
+
+	rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status);
+	if (rc)
+		return rc;
+
+	pc_ready = ctrl_status & CTRL_STATUS_PC_READY_IRIS3;
+	idle_status = ctrl_status & BIT(30);
+
+	if (pc_ready) {
+		d_vpr_h("Already in pc_ready state\n");
+		return 0;
+	}
+	rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status);
+	if (rc)
+		return rc;
+
+	wfi_status &= BIT(0);
+	if (!wfi_status || !idle_status) {
+		d_vpr_e("Skipping PC, wfi status not set\n");
+		goto skip_power_off;
+	}
+
+	rc = __prepare_pc(core);
+	if (rc) {
+		d_vpr_e("Failed __prepare_pc %d\n", rc);
+		goto skip_power_off;
+	}
+
+	rc = __read_register_with_poll_timeout(core, CTRL_STATUS_IRIS3,
+					       CTRL_STATUS_PC_READY_IRIS3,
+					       CTRL_STATUS_PC_READY_IRIS3, 250, 2500);
+	if (rc) {
+		d_vpr_e("%s: Skip PC. Ctrl status not set\n", __func__);
+		goto skip_power_off;
+	}
+
+	rc = __read_register_with_poll_timeout(core, WRAPPER_TZ_CPU_STATUS,
+					       BIT(0), 0x1, 250, 2500);
+	if (rc) {
+		d_vpr_e("%s: Skip PC. Wfi status not set\n", __func__);
+		goto skip_power_off;
+	}
+	return rc;
+
+skip_power_off:
+	rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status);
+	if (rc)
+		return rc;
+	rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status);
+	if (rc)
+		return rc;
+	wfi_status &= BIT(0);
+	d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n",
+		wfi_status, idle_status, pc_ready, ctrl_status);
+	return -EAGAIN;
+}
+
+static int __raise_interrupt_iris3(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	rc = __write_register(core, CPU_IC_SOFTINT_IRIS3, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS3);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int __watchdog_iris3(struct msm_vidc_core *core, u32 intr_status)
+{
+	int rc = 0;
+
+	if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3) {
+		d_vpr_e("%s: received watchdog interrupt\n", __func__);
+		rc = 1;
+	}
+
+	return rc;
+}
+
+static int __clear_interrupt_iris3(struct msm_vidc_core *core)
+{
+	u32 intr_status = 0, mask = 0;
+	int rc = 0;
+
+	rc = __read_register(core, WRAPPER_INTR_STATUS_IRIS3, &intr_status);
+	if (rc)
+		return rc;
+
+	mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3 |
+		WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 |
+		CTRL_INIT_IDLE_MSG_BMSK_IRIS3);
+
+	if (intr_status & mask) {
+		core->intr_status |= intr_status;
+		core->reg_count++;
+		d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n",
+			core->reg_count, intr_status);
+	} else {
+		core->spur_count++;
+	}
+
+	rc = __write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS3, 1);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int __boot_firmware_iris3(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000;
+
+	rc = __setup_ucregion_memory_map_iris3(core);
+	if (rc)
+		return rc;
+
+	ctrl_init_val = BIT(0);
+
+	rc = __write_register(core, CTRL_INIT_IRIS3, ctrl_init_val);
+	if (rc)
+		return rc;
+
+	while (!ctrl_status && count < max_tries) {
+		rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status);
+		if (rc)
+			return rc;
+
+		if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS3) == 0x4) {
+			d_vpr_e("invalid setting for UC_REGION\n");
+			break;
+		}
+
+		usleep_range(50, 100);
+		count++;
+	}
+
+	if (count >= max_tries) {
+		d_vpr_e("Error booting up vidc firmware\n");
+		return -ETIME;
+	}
+
+	/* Enable interrupt before sending commands to venus */
+	rc = __write_register(core, CPU_CS_H2XSOFTINTEN_IRIS3, 0x1);
+	if (rc)
+		return rc;
+
+	rc = __write_register(core, CPU_CS_X2RPMH_IRIS3, 0x0);
+
+	return rc;
+}
+
+int msm_vidc_decide_work_mode_iris3(struct msm_vidc_inst *inst)
+{
+	u32 work_mode;
+	struct v4l2_format *inp_f;
+	u32 width, height;
+	bool res_ok = false;
+
+	work_mode = MSM_VIDC_STAGE_2;
+	inp_f = &inst->fmts[INPUT_PORT];
+
+	if (is_decode_session(inst)) {
+		height = inp_f->fmt.pix_mp.height;
+		width = inp_f->fmt.pix_mp.width;
+		res_ok = res_is_less_than(width, height, 1280, 720);
+		if (inst->capabilities[CODED_FRAMES].value ==
+				CODED_FRAMES_INTERLACE || res_ok) {
+			work_mode = MSM_VIDC_STAGE_1;
+		}
+	} else if (is_encode_session(inst)) {
+		height = inst->crop.height;
+		width = inst->crop.width;
+		res_ok = !res_is_greater_than(width, height, 4096, 2160);
+		if (inst->capabilities[SLICE_MODE].value ==
+			V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
+			work_mode = MSM_VIDC_STAGE_1;
+		}
+		if (inst->capabilities[LOSSLESS].value)
+			work_mode = MSM_VIDC_STAGE_2;
+
+		if (!inst->capabilities[GOP_SIZE].value)
+			work_mode = MSM_VIDC_STAGE_2;
+	} else {
+		i_vpr_e(inst, "%s: invalid session type\n", __func__);
+		return -EINVAL;
+	}
+
+	i_vpr_h(inst, "Configuring work mode = %u gop size = %u\n",
+		work_mode, inst->capabilities[GOP_SIZE].value);
+	msm_vidc_update_cap_value(inst, STAGE, work_mode, __func__);
+
+	return 0;
+}
+
+int msm_vidc_decide_work_route_iris3(struct msm_vidc_inst *inst)
+{
+	u32 work_route;
+	struct msm_vidc_core *core;
+
+	core = inst->core;
+	work_route = core->capabilities[NUM_VPP_PIPE].value;
+
+	if (is_decode_session(inst)) {
+		if (inst->capabilities[CODED_FRAMES].value ==
+				CODED_FRAMES_INTERLACE)
+			work_route = MSM_VIDC_PIPE_1;
+	} else if (is_encode_session(inst)) {
+		u32 slice_mode;
+
+		slice_mode = inst->capabilities[SLICE_MODE].value;
+
+		/*TODO Pipe=1 for legacy CBR*/
+		if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES)
+			work_route = MSM_VIDC_PIPE_1;
+
+	} else {
+		i_vpr_e(inst, "%s: invalid session type\n", __func__);
+		return -EINVAL;
+	}
+
+	i_vpr_h(inst, "Configuring work route = %u", work_route);
+	msm_vidc_update_cap_value(inst, PIPE, work_route, __func__);
+
+	return 0;
+}
+
+int msm_vidc_decide_quality_mode_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps;
+	u32 mode = MSM_VIDC_POWER_SAVE_MODE;
+
+	if (!is_encode_session(inst))
+		return 0;
+
+	/* lossless or all intra runs at quality mode */
+	if (inst->capabilities[LOSSLESS].value ||
+	    inst->capabilities[ALL_INTRA].value) {
+		mode = MSM_VIDC_MAX_QUALITY_MODE;
+		goto decision_done;
+	}
+
+	mbpf = msm_vidc_get_mbs_per_frame(inst);
+	mbps = mbpf * msm_vidc_get_fps(inst);
+	core = inst->core;
+	max_hq_mbpf = core->capabilities[MAX_MBPF_HQ].value;
+	max_hq_mbps = core->capabilities[MAX_MBPS_HQ].value;
+
+	if (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps)
+		mode = MSM_VIDC_MAX_QUALITY_MODE;
+
+decision_done:
+	msm_vidc_update_cap_value(inst, QUALITY_MODE, mode, __func__);
+
+	return 0;
+}
+
+int msm_vidc_adjust_bitrate_boost_iris3(void *instance, struct v4l2_ctrl *ctrl)
+{
+	s32 adjusted_value;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	s32 rc_type = -1;
+	u32 width, height, frame_rate;
+	struct v4l2_format *f;
+	u32 max_bitrate = 0, bitrate = 0;
+
+	adjusted_value = ctrl ? ctrl->val :
+		inst->capabilities[BITRATE_BOOST].value;
+
+	if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
+		return 0;
+
+	if (msm_vidc_get_parent_value(inst, BITRATE_BOOST,
+				      BITRATE_MODE, &rc_type, __func__))
+		return -EINVAL;
+
+	/*
+	 * Bitrate Boost are supported only for VBR rc type.
+	 * Hence, do not adjust or set to firmware for non VBR rc's
+	 */
+	if (rc_type != HFI_RC_VBR_CFR) {
+		adjusted_value = 0;
+		goto adjust;
+	}
+
+	frame_rate = inst->capabilities[FRAME_RATE].value >> 16;
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	/*
+	 * honor client set bitrate boost
+	 * if client did not set, keep max bitrate boost up to 4k@60fps
+	 * and remove bitrate boost after 4k@60fps
+	 */
+	if (inst->capabilities[BITRATE_BOOST].flags & CAP_FLAG_CLIENT_SET) {
+		/* accept client set bitrate boost value as is */
+	} else {
+		if (res_is_less_than_or_equal_to(width, height, 4096, 2176) &&
+		    frame_rate <= 60)
+			adjusted_value = MAX_BITRATE_BOOST;
+		else
+			adjusted_value = 0;
+	}
+
+	max_bitrate = msm_vidc_get_max_bitrate(inst);
+	bitrate = inst->capabilities[BIT_RATE].value;
+	if (adjusted_value) {
+		if ((bitrate + bitrate / (100 / adjusted_value)) > max_bitrate) {
+			i_vpr_h(inst,
+				"%s: bitrate %d is beyond max bitrate %d, remove bitrate boost\n",
+				__func__, max_bitrate, bitrate);
+			adjusted_value = 0;
+		}
+	}
+adjust:
+	msm_vidc_update_cap_value(inst, BITRATE_BOOST, adjusted_value, __func__);
+
+	return 0;
+}
+
+static struct msm_vidc_iris_ops iris3_ops = {
+	.boot_firmware = __boot_firmware_iris3,
+	.raise_interrupt = __raise_interrupt_iris3,
+	.clear_interrupt = __clear_interrupt_iris3,
+	.power_on = __power_on_iris3,
+	.power_off = __power_off_iris3,
+	.prepare_pc = __prepare_pc_iris3,
+	.watchdog = __watchdog_iris3,
+};
+
+static struct msm_vidc_session_ops msm_session_ops = {
+	.buffer_size = msm_buffer_size_iris3,
+	.min_count = msm_buffer_min_count_iris3,
+	.extra_count = msm_buffer_extra_count_iris3,
+	.calc_freq = msm_vidc_calc_freq_iris3,
+	.calc_bw = msm_vidc_calc_bw_iris3,
+	.decide_work_route = msm_vidc_decide_work_route_iris3,
+	.decide_work_mode = msm_vidc_decide_work_mode_iris3,
+	.decide_quality_mode = msm_vidc_decide_quality_mode_iris3,
+};
+
+int msm_vidc_init_iris3(struct msm_vidc_core *core)
+{
+	core->iris_ops = &iris3_ops;
+	core->session_ops = &msm_session_ops;
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (27 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 28/33] iris: variant: iris3: add iris3 specific ops Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 14:19   ` Dmitry Baryshkov
  2023-07-28 13:23 ` [PATCH 30/33] iris: variant: iris3: add helper for bus and clock calculation Vikash Garodia
                   ` (6 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements iris3 specific buffer size calculation for
firmware internal buffers, input and output buffers for
encoder and decoder.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 ++++++++++++++++++++
 .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
 .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 ++++++++
 3 files changed, 2095 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c

diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
new file mode 100644
index 0000000..cb068ca
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
@@ -0,0 +1,1481 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __HFI_BUFFER_IRIS3__
+#define __HFI_BUFFER_IRIS3__
+
+#include <linux/types.h>
+
+#include "hfi_property.h"
+
+typedef u8      HFI_U8;
+typedef s8      HFI_S8;
+typedef u16     HFI_U16;
+typedef s16     HFI_S16;
+typedef u32     HFI_U32;
+typedef s32     HFI_S32;
+typedef u64     HFI_U64;
+typedef u32     HFI_BOOL;
+
+#ifndef MIN
+#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#define HFI_ALIGNMENT_4096 (4096)
+
+#define BUF_SIZE_ALIGN_16 (16)
+#define BUF_SIZE_ALIGN_32 (32)
+#define BUF_SIZE_ALIGN_64 (64)
+#define BUF_SIZE_ALIGN_128 (128)
+#define BUF_SIZE_ALIGN_256 (256)
+#define BUF_SIZE_ALIGN_512 (512)
+#define BUF_SIZE_ALIGN_4096 (4096)
+
+#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \
+	(b) * (b)) : (((a) + (b) - 1) & (~((b) - 1))))
+
+#define HFI_WORKMODE_1 1
+#define HFI_WORKMODE_2 2
+
+#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64)
+#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16)
+
+#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8)
+#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32)
+#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8)
+#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16)
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4)
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48)
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4)
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24)
+#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4)
+#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16)
+
+#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = HFI_ALIGN(frame_width, stride_multiple))
+
+#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
+	min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \
+	min_buf_height_multiple))
+
+#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = HFI_ALIGN(frame_width, stride_multiple))
+
+#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
+	min_buf_height_multiple) (buf_height = HFI_ALIGN((((frame_height) + 1) \
+	 >> 1),	min_buf_height_multiple))
+
+#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufsize, y_stride, y_buf_height, \
+	uv_buf_size, uv_stride, uv_buf_height) \
+	do { \
+		y_bufsize = (y_stride * y_buf_height); \
+		uv_buf_size = (uv_stride * uv_buf_height); \
+		buf_size = HFI_ALIGN(y_bufsize + uv_buf_size, HFI_ALIGNMENT_4096) \
+	} while (0)
+
+#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufsize, y_stride, y_buf_height) \
+	(y_bufsize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
+
+#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \
+	uv_stride, uv_buf_height) \
+	(uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096))
+
+#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\
+	frame_width, frame_height, y_stride_multiple,\
+	y_buffer_height_multiple, uv_stride_multiple, \
+	uv_buffer_height_multiple, y_metadata_stride_multiple, \
+	y_metadata_buffer_height_multiple, \
+	uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \
+	do { \
+		HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size;   \
+		HFI_U32 stride, _height; \
+		HFI_U32 half_height = (frame_height + 1) >> 1; \
+		HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\
+					y_stride_multiple); \
+		HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\
+					y_buffer_height_multiple); \
+		HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\
+		HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \
+					uv_stride_multiple); \
+		HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \
+					uv_buffer_height_multiple); \
+		HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\
+		HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\
+				y_metadata_stride_multiple, \
+			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\
+		HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \
+				y_metadata_buffer_height_multiple,\
+			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\
+		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \
+				_height);    \
+		HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\
+				uv_metadata_stride_multiple, \
+			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \
+		HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\
+				uv_metadata_buffer_height_multiple,\
+			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\
+		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \
+				 _height); \
+		buf_size = (y_buf_size + uv_buf_size + y_meta_size + \
+			uv_meta_size) << 1;\
+	} while (0)
+
+#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+	do { \
+		stride = HFI_ALIGN(frame_width, 192); \
+		stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
+	} while (0)
+
+#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
+				min_buf_height_multiple) \
+	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
+
+#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+	do { \
+		stride = HFI_ALIGN(frame_width, 192); \
+		stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
+	} while (0)
+
+#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
+				min_buf_height_multiple) \
+	(buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
+			min_buf_height_multiple))
+
+#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\
+		y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \
+	do {	\
+		y_buf_size = (y_stride * y_buf_height); \
+		uv_buf_size = (uv_stride * uv_buf_height); \
+		buf_size = y_buf_size + uv_buf_size \
+	} while (0)
+
+#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \
+					y_buf_height) \
+	(y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
+
+#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \
+					uv_buf_height) \
+	(uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096))
+
+#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride, y_buf_height, \
+	uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \
+	uv_md_height)\
+	do { \
+		HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \
+		HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\
+						y_buf_height); \
+		HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \
+						uv_buf_height); \
+		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \
+						y_md_height); \
+		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \
+						uv_md_height); \
+		buf_size = y_data_size + uv_data_size + y_md_size + \
+						uv_md_size; \
+	} while (0)
+
+#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = HFI_ALIGN(frame_width * 2, stride_multiple))
+
+#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
+				min_buf_height_multiple) \
+	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
+
+#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = HFI_ALIGN(frame_width * 2, stride_multiple))
+
+#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
+				min_buf_height_multiple) \
+	(buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
+			min_buf_height_multiple))
+
+#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \
+	y_buf_height, uv_data_size, uv_stride, uv_buf_height) \
+	do { \
+		y_data_size = HFI_ALIGN(y_stride * y_buf_height, \
+				HFI_ALIGNMENT_4096);\
+		uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \
+				HFI_ALIGNMENT_4096); \
+		buf_size = y_data_size + uv_data_size; \
+	} while (0)
+
+#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = ((frame_width * 3) + stride_multiple - 1) & \
+			 (0xffffffff - (stride_multiple - 1)))
+
+#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \
+			min_buf_height_multiple) \
+	(buf_height = ((frame_height + min_buf_height_multiple - 1) & \
+			(0xffffffff - (min_buf_height_multiple - 1))))
+
+#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
+	(buf_size = ((stride) * (buf_height)))
+
+#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \
+	(stride = HFI_ALIGN((frame_width << 2), stride_multiple))
+
+#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \
+			min_buf_height_multiple) \
+	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
+
+#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
+	(buf_size = (stride) * (buf_height))
+
+#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \
+				buf_height) \
+	(buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096))
+
+#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \
+	metadata_buffer_size, stride, buf_height, _metadata_tride, \
+	_metadata_buf_height) \
+	do { \
+		HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \
+				stride, buf_height); \
+		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \
+				_metadata_tride, _metadata_buf_height); \
+		buf_size = data_buf_size + metadata_buffer_size \
+	} while (0)
+
+#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\
+	metadata_stride_multiple, tile_width_in_pels) \
+	((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels - 1)) /\
+	tile_width_in_pels), metadata_stride_multiple)))
+
+#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height, \
+	metadata_height_multiple, tile_height_in_pels) \
+	((metadata_buf_height = HFI_ALIGN(((frame_height + \
+	(tile_height_in_pels - 1)) / tile_height_in_pels), \
+	metadata_height_multiple)))
+
+#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \
+	metadata_stride_multiple, tile_width_in_pels) \
+	((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\
+	(tile_width_in_pels - 1)) / tile_width_in_pels), \
+	metadata_stride_multiple)))
+
+#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height,\
+	metadata_height_multiple, tile_height_in_pels) \
+	(metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \
+	(tile_height_in_pels - 1)) / tile_height_in_pels), \
+	metadata_height_multiple))
+
+#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \
+					_metadata_buf_height) \
+	((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \
+					HFI_ALIGNMENT_4096)))
+
+#define BUFFER_ALIGNMENT_512_BYTES 512
+#define BUFFER_ALIGNMENT_256_BYTES 256
+#define BUFFER_ALIGNMENT_128_BYTES 128
+#define BUFFER_ALIGNMENT_64_BYTES 64
+#define BUFFER_ALIGNMENT_32_BYTES 32
+#define BUFFER_ALIGNMENT_16_BYTES 16
+#define BUFFER_ALIGNMENT_8_BYTES 8
+#define BUFFER_ALIGNMENT_4_BYTES 4
+
+#define VENUS_DMA_ALIGNMENT BUFFER_ALIGNMENT_256_BYTES
+
+#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64
+#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64
+#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64
+#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640
+#define MAX_FE_NBR_DATA_CB_LINE_BUFFER_SIZE 320
+#define MAX_FE_NBR_DATA_CR_LINE_BUFFER_SIZE 320
+
+#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE (128 / 8)
+#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8)
+#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8)
+
+#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE (64 * 2 * 3)
+#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE (32 * 2 * 3)
+#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE (16 * 2 * 3)
+
+#define MAX_TILE_COLUMNS 32
+
+#define SIZE_VPSS_LB(size, frame_width, frame_height, num_vpp_pipes) \
+	do { \
+		HFI_U32 vpss_4tap_top_buffer_size, vpss_div2_top_buffer_size, \
+		vpss_4tap_left_buffer_size, vpss_div2_left_buffer_size; \
+		HFI_U32 opb_wr_top_line_luma_buffer_size, \
+		opb_wr_top_line_chroma_buffer_size, \
+		opb_lb_wr_llb_y_buffer_size,\
+		opb_lb_wr_llb_uv_buffer_size; \
+		HFI_U32 macrotiling_size; \
+		vpss_4tap_top_buffer_size = 0; \
+		vpss_div2_top_buffer_size = 0; \
+		vpss_4tap_left_buffer_size = 0; \
+		vpss_div2_left_buffer_size = 0; \
+		macrotiling_size = 32; \
+		opb_wr_top_line_luma_buffer_size = HFI_ALIGN(frame_width, \
+			macrotiling_size) / macrotiling_size * 256; \
+			opb_wr_top_line_luma_buffer_size = \
+		HFI_ALIGN(opb_wr_top_line_luma_buffer_size, \
+		VENUS_DMA_ALIGNMENT) + (MAX_TILE_COLUMNS - 1) * 256; \
+		opb_wr_top_line_luma_buffer_size = \
+		MAX(opb_wr_top_line_luma_buffer_size, (32 * \
+			HFI_ALIGN(frame_height, 8))); \
+		opb_wr_top_line_chroma_buffer_size = \
+			opb_wr_top_line_luma_buffer_size;\
+		opb_lb_wr_llb_uv_buffer_size = \
+			HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\
+					   BUFFER_ALIGNMENT_32_BYTES); \
+		opb_lb_wr_llb_y_buffer_size = \
+			HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\
+					   BUFFER_ALIGNMENT_32_BYTES); \
+		size = num_vpp_pipes * 2 * (vpss_4tap_top_buffer_size +  \
+						vpss_div2_top_buffer_size) +  \
+			   2 * (vpss_4tap_left_buffer_size + \
+					vpss_div2_left_buffer_size) + \
+			   opb_wr_top_line_luma_buffer_size + \
+			   opb_wr_top_line_chroma_buffer_size + \
+			   opb_lb_wr_llb_uv_buffer_size + \
+			   opb_lb_wr_llb_y_buffer_size; \
+	} while (0)
+
+#define VPP_CMD_MAX_SIZE (1 << 20)
+#define NUM_HW_PIC_BUF 32
+#define BIN_BUFFER_THRESHOLD (1280 * 736)
+#define H264D_MAX_SLICE 1800
+#define SIZE_H264D_BUFTAB_T (256)
+#define SIZE_H264D_HW_PIC_T (1 << 11)
+#define SIZE_H264D_BSE_CMD_PER_BUF (32 * 4)
+#define SIZE_H264D_VPP_CMD_PER_BUF (512)
+
+#define SIZE_H264D_LB_FE_TOP_DATA(frame_width, frame_height) \
+	(MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * HFI_ALIGN(frame_width, 16) * 3)
+
+#define SIZE_H264D_LB_FE_TOP_CTRL(frame_width, frame_height) \
+	(MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4))
+
+#define SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, frame_height) \
+	(MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4))
+
+#define SIZE_H264D_LB_SE_TOP_CTRL(frame_width, frame_height) \
+	(MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4))
+
+#define SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, frame_height) \
+	(MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4))
+
+#define SIZE_H264D_LB_PE_TOP_DATA(frame_width, frame_height) \
+	(MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE *  ((frame_width + 15) >> 4))
+
+#define SIZE_H264D_LB_VSP_TOP(frame_width, frame_height) \
+	((((frame_width + 15) >> 4) << 7))
+
+#define SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \
+	(HFI_ALIGN(frame_height, 16) * 32)
+
+#define SIZE_H264D_QP(frame_width, frame_height) \
+	(((frame_width + 63) >> 6) * ((frame_height + 63) >> 6) * 128)
+
+#define SIZE_HW_PIC(size_per_buf) \
+	(NUM_HW_PIC_BUF * size_per_buf)
+
+#define SIZE_H264D_BSE_CMD_BUF(_size, frame_width, frame_height) \
+	do { \
+		HFI_U32 _height = HFI_ALIGN(frame_height, \
+				BUFFER_ALIGNMENT_32_BYTES);  \
+		_size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) *\
+					  SIZE_H264D_BSE_CMD_PER_BUF; \
+	} while (0)
+
+#define SIZE_H264D_VPP_CMD_BUF(_size, frame_width, frame_height)    \
+	do { \
+		HFI_U32 _height = HFI_ALIGN(frame_height, \
+				BUFFER_ALIGNMENT_32_BYTES); \
+		_size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) * \
+					SIZE_H264D_VPP_CMD_PER_BUF; \
+		if (_size > VPP_CMD_MAX_SIZE) \
+			_size = VPP_CMD_MAX_SIZE; \
+	} while (0)
+
+#define HFI_BUFFER_COMV_H264D(comv_size, frame_width, \
+			frame_height, _comv_bufcount) \
+	do { \
+		HFI_U32 frame_width_in_mbs = ((frame_width + 15) >> 4); \
+		HFI_U32 frame_height_in_mbs = ((frame_height + 15) >> 4); \
+		HFI_U32 col_mv_aligned_width = (frame_width_in_mbs << 7); \
+		HFI_U32 col_zero_aligned_width = (frame_width_in_mbs << 2); \
+		HFI_U32 col_zero_size = 0, size_colloc = 0; \
+		col_mv_aligned_width = HFI_ALIGN(col_mv_aligned_width, \
+					BUFFER_ALIGNMENT_16_BYTES); \
+		col_zero_aligned_width = HFI_ALIGN(col_zero_aligned_width, \
+					BUFFER_ALIGNMENT_16_BYTES); \
+		col_zero_size = col_zero_aligned_width * \
+					((frame_height_in_mbs + 1) >> 1); \
+		col_zero_size = HFI_ALIGN(col_zero_size, \
+				BUFFER_ALIGNMENT_64_BYTES);  \
+		col_zero_size <<= 1; \
+		col_zero_size = HFI_ALIGN(col_zero_size, \
+				BUFFER_ALIGNMENT_512_BYTES); \
+		size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + \
+				1) >> 1); \
+		size_colloc = HFI_ALIGN(size_colloc, \
+				BUFFER_ALIGNMENT_64_BYTES); \
+		size_colloc <<= 1; \
+		size_colloc = HFI_ALIGN(size_colloc, \
+				BUFFER_ALIGNMENT_512_BYTES); \
+		size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2); \
+		comv_size = size_colloc * (_comv_bufcount); \
+		comv_size += BUFFER_ALIGNMENT_512_BYTES; \
+	} while (0)
+
+#define HFI_BUFFER_NON_COMV_H264D(_size, frame_width, frame_height, \
+								num_vpp_pipes) \
+	do { \
+		HFI_U32 _size_bse, _size_vpp; \
+		SIZE_H264D_BSE_CMD_BUF(_size_bse, frame_width, frame_height); \
+		SIZE_H264D_VPP_CMD_BUF(_size_vpp, frame_width, frame_height); \
+		_size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), \
+			VENUS_DMA_ALIGNMENT); \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define HFI_BUFFER_LINE_H264D(_size, frame_width, frame_height, \
+							  is_opb, num_vpp_pipes)            \
+	do { \
+		HFI_U32 vpss_lb_size = 0; \
+		_size = HFI_ALIGN(SIZE_H264D_LB_FE_TOP_DATA(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H264D_LB_FE_TOP_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+			HFI_ALIGN(SIZE_H264D_LB_SE_TOP_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) * \
+			num_vpp_pipes + \
+			HFI_ALIGN(SIZE_H264D_LB_PE_TOP_DATA(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H264D_LB_VSP_TOP(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H264D_LB_RECON_DMA_METADATA_WR\
+			(frame_width, frame_height), \
+			VENUS_DMA_ALIGNMENT) * 2 + HFI_ALIGN(SIZE_H264D_QP\
+			(frame_width, frame_height), VENUS_DMA_ALIGNMENT); \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+		if (is_opb) { \
+			SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \
+						num_vpp_pipes); \
+		} \
+		_size = HFI_ALIGN((_size + vpss_lb_size), \
+			VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define H264_CABAC_HDR_RATIO_HD_TOT 1
+#define H264_CABAC_RES_RATIO_HD_TOT 3
+
+#define SIZE_H264D_HW_BIN_BUFFER(_size, frame_width, frame_height, \
+				delay, num_vpp_pipes) \
+	do { \
+		HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \
+		size_yuv = ((frame_width * frame_height) <= \
+			BIN_BUFFER_THRESHOLD) ?\
+			((BIN_BUFFER_THRESHOLD * 3) >> 1) : \
+			((frame_width * frame_height * 3) >> 1); \
+		size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT; \
+		size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT; \
+		size_bin_hdr = size_bin_hdr * (((((HFI_U32)(delay)) & 31) /\
+				10) + 2) / 2; \
+		size_bin_res = size_bin_res * (((((HFI_U32)(delay)) & 31) /\
+				10) + 2) / 2; \
+		size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes,\
+				VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \
+		size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \
+			VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \
+		_size = size_bin_hdr + size_bin_res; \
+	} while (0)
+
+#define HFI_BUFFER_BIN_H264D(_size, frame_width, frame_height, is_interlaced, \
+			delay, num_vpp_pipes) \
+	do { \
+		HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \
+				BUFFER_ALIGNMENT_16_BYTES);\
+		HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \
+				BUFFER_ALIGNMENT_16_BYTES); \
+		if (!is_interlaced)  { \
+			SIZE_H264D_HW_BIN_BUFFER(_size, n_aligned_w, \
+				n_aligned_h, delay, num_vpp_pipes); \
+		} else \
+			_size = 0;  \
+	} while (0)
+
+#define NUM_SLIST_BUF_H264 (256 + 32)
+#define SIZE_SLIST_BUF_H264 (512)
+#define SIZE_SEI_USERDATA (4096)
+#define H264_NUM_FRM_INFO (66)
+#define H264_DISPLAY_BUF_SIZE (3328)
+#define SIZE_DOLBY_RPU_METADATA (41 * 1024)
+#define HFI_BUFFER_PERSIST_H264D(_size, rpu_enabled) \
+	(_size = HFI_ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 + \
+	H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO + \
+	NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \
+	(rpu_enabled) * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), \
+	VENUS_DMA_ALIGNMENT))
+
+#define LCU_MAX_SIZE_PELS 64
+#define LCU_MIN_SIZE_PELS 16
+
+#define H265D_MAX_SLICE 1200
+#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T
+#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(HFI_U32))
+#define SIZE_H265D_VPP_CMD_PER_BUF (256)
+
+#define SIZE_H265D_LB_FE_TOP_DATA(frame_width, frame_height) \
+	(MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \
+	(HFI_ALIGN(frame_width, 64) + 8) * 2)
+
+#define SIZE_H265D_LB_FE_TOP_CTRL(frame_width, frame_height) \
+	(MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \
+	(HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS))
+
+#define SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, frame_height) \
+	(MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \
+	(HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS))
+
+#define SIZE_H265D_LB_SE_TOP_CTRL(frame_width, frame_height) \
+	((LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4))
+
+#define SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, frame_height)    \
+	(MAX(((frame_height + 16 - 1) / 8) * \
+		MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,     \
+	MAX(((frame_height + 32 - 1) / 8) * \
+		MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \
+	((frame_height + 64 - 1) / 8) * \
+		MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)))
+
+#define SIZE_H265D_LB_PE_TOP_DATA(frame_width, frame_height) \
+	(MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * (HFI_ALIGN(frame_width, \
+	LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS))
+
+#define SIZE_H265D_LB_VSP_TOP(frame_width, frame_height) \
+	(((frame_width + 63) >> 6) * 128)
+
+#define SIZE_H265D_LB_VSP_LEFT(frame_width, frame_height) \
+	(((frame_height + 63) >> 6) * 128)
+
+#define SIZE_H265D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \
+	SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height)
+
+#define SIZE_H265D_QP(frame_width, frame_height) \
+		SIZE_H264D_QP(frame_width, frame_height)
+
+#define SIZE_H265D_BSE_CMD_BUF(_size, frame_width, frame_height)\
+	do { \
+		_size = HFI_ALIGN(((HFI_ALIGN(frame_width, \
+		LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * \
+		(HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) /\
+		LCU_MIN_SIZE_PELS)) * NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT);  \
+		_size = MIN(_size, H265D_MAX_SLICE + 1);          \
+		_size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF;     \
+	} while (0)
+
+#define SIZE_H265D_VPP_CMD_BUF(_size, frame_width, frame_height)  \
+	do { \
+		_size = HFI_ALIGN(((HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) /\
+		LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \
+		LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * \
+		NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT);  \
+		_size = MIN(_size, H265D_MAX_SLICE + 1);    \
+		_size = HFI_ALIGN(_size, 4);  \
+		_size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; \
+		if (_size > VPP_CMD_MAX_SIZE) { \
+			_size = VPP_CMD_MAX_SIZE;   \
+		}                          \
+	} while (0)
+
+#define HFI_BUFFER_COMV_H265D(_size, frame_width, frame_height, \
+							_comv_bufcount) \
+	do { \
+		_size = HFI_ALIGN(((((frame_width + 15) >> 4) * \
+			((frame_height + 15) >> 4)) << 8), \
+			BUFFER_ALIGNMENT_512_BYTES); \
+		_size *= _comv_bufcount; \
+		_size += BUFFER_ALIGNMENT_512_BYTES; \
+	} while (0)
+
+#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024)
+
+#define HFI_BUFFER_NON_COMV_H265D(_size, frame_width, frame_height, \
+				num_vpp_pipes) \
+	do { \
+		HFI_U32 _size_bse, _size_vpp; \
+		SIZE_H265D_BSE_CMD_BUF(_size_bse, frame_width, \
+		frame_height); \
+		SIZE_H265D_VPP_CMD_BUF(_size_vpp, frame_width, \
+		frame_height);  \
+		_size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) +     \
+			HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) +     \
+			HFI_ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, \
+			VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(2 * sizeof(HFI_U16) *           \
+			(HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / \
+			LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \
+			LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), \
+			VENUS_DMA_ALIGNMENT) +                \
+			HFI_ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), \
+			VENUS_DMA_ALIGNMENT) + \
+			HDR10_HIST_EXTRADATA_SIZE;           \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT);  \
+	} while (0)
+
+#define HFI_BUFFER_LINE_H265D(_size, frame_width, frame_height, \
+			is_opb, num_vpp_pipes) \
+	do { \
+		HFI_U32 vpss_lb_size = 0; \
+		_size = HFI_ALIGN(SIZE_H265D_LB_FE_TOP_DATA(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H265D_LB_FE_TOP_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+			HFI_ALIGN(SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+			HFI_ALIGN(SIZE_H265D_LB_SE_TOP_CTRL(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H265D_LB_PE_TOP_DATA(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) + \
+			HFI_ALIGN(SIZE_H265D_LB_VSP_TOP(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) +        \
+			HFI_ALIGN(SIZE_H265D_LB_VSP_LEFT(frame_width, \
+			frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+			HFI_ALIGN(SIZE_H265D_LB_RECON_DMA_METADATA_WR\
+			(frame_width, frame_height), \
+			VENUS_DMA_ALIGNMENT) * 4 +  \
+			HFI_ALIGN(SIZE_H265D_QP(frame_width, frame_height),\
+			VENUS_DMA_ALIGNMENT);           \
+		if (is_opb) { \
+			SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height,\
+						 num_vpp_pipes); \
+		} \
+		_size = HFI_ALIGN((_size + vpss_lb_size), \
+			VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define H265_CABAC_HDR_RATIO_HD_TOT 2
+#define H265_CABAC_RES_RATIO_HD_TOT 2
+
+#define SIZE_H265D_HW_BIN_BUFFER(_size, frame_width, frame_height, \
+				delay, num_vpp_pipes)    \
+	do { \
+		HFI_U32 size_yuv, size_bin_hdr, size_bin_res;     \
+		size_yuv = ((frame_width * frame_height) <= \
+			BIN_BUFFER_THRESHOLD) ? \
+			((BIN_BUFFER_THRESHOLD * 3) >> 1) : \
+			((frame_width * frame_height * 3) >> 1); \
+		size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT;    \
+		size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT;   \
+		size_bin_hdr = size_bin_hdr * \
+			(((((HFI_U32)(delay)) & 31) / 10) + 2) / 2;    \
+		size_bin_res = size_bin_res * \
+			(((((HFI_U32)(delay)) & 31) / 10) + 2) / 2;    \
+		size_bin_hdr = HFI_ALIGN(size_bin_hdr / \
+			num_vpp_pipes, VENUS_DMA_ALIGNMENT) * \
+			num_vpp_pipes;  \
+		size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes,\
+			VENUS_DMA_ALIGNMENT) * num_vpp_pipes;  \
+		_size = size_bin_hdr + size_bin_res;    \
+	} while (0)
+
+#define HFI_BUFFER_BIN_H265D(_size, frame_width, frame_height, \
+				is_interlaced, delay, num_vpp_pipes) \
+	do { \
+		HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \
+				BUFFER_ALIGNMENT_16_BYTES); \
+		HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \
+				BUFFER_ALIGNMENT_16_BYTES); \
+		if (!is_interlaced) { \
+			SIZE_H265D_HW_BIN_BUFFER(_size, n_aligned_w, \
+			n_aligned_h, delay, num_vpp_pipes); \
+		} else \
+			_size = 0; \
+	} while (0)
+
+#define SIZE_SLIST_BUF_H265 (1 << 10)
+#define NUM_SLIST_BUF_H265 (80 + 20)
+#define H265_NUM_TILE_COL 32
+#define H265_NUM_TILE_ROW 128
+#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1)
+#define H265_NUM_FRM_INFO (48)
+#define H265_DISPLAY_BUF_SIZE (3072)
+#define HFI_BUFFER_PERSIST_H265D(_size, rpu_enabled) \
+	(_size = HFI_ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + \
+	H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + \
+	H265_NUM_TILE * sizeof(HFI_U32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \
+	rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA),\
+	VENUS_DMA_ALIGNMENT))
+
+#define SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, frame_height) \
+	MAX(((frame_height + 15) >> 4) * \
+	MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \
+	MAX(((frame_height + 31) >> 5) * \
+	MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \
+	((frame_height + 63) >> 6) * MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))
+#define SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height) \
+	(((HFI_ALIGN(frame_width, 64) + 8) * 10 * 2))
+#define SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height) \
+	(((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE)
+#define SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height)  \
+	MAX(((frame_height + 15) >> 4) * \
+	MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,\
+	MAX(((frame_height + 31) >> 5) * \
+	MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \
+	((frame_height + 63) >> 6) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))
+#define SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \
+	HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\
+	BUFFER_ALIGNMENT_32_BYTES)
+#define SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height) \
+	((HFI_ALIGN(frame_width, 16) + 8) * 10 * 2)
+#define SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height) \
+	((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) + 8) * 10 * 2)
+#define SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height) \
+	((HFI_ALIGN(frame_width, 16) >> 4) * 64)
+#define SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height) \
+	((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 176)
+#define SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height) \
+	(((HFI_ALIGN(frame_width, 16) >> 4) * 64 / 2) + 256)
+#define SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height) \
+	((((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256))
+
+#define HFI_IRIS3_VP9D_COMV_SIZE \
+	((((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8))
+
+#define SIZE_VP9D_QP(frame_width, frame_height) \
+	SIZE_H264D_QP(frame_width, frame_height)
+
+#define HFI_IRIS3_VP9D_LB_SIZE(_size, frame_width, frame_height, num_vpp_pipes)\
+		(_size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \
+		frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+		HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\
+		VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+		HFI_ALIGN(SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + 2 * \
+		HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR \
+		(frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VP9D_QP(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT))
+
+#define HFI_BUFFER_LINE_VP9D(_size, frame_width, frame_height, \
+		_yuv_bufcount_min, is_opb, num_vpp_pipes) \
+	do { \
+		HFI_U32 _lb_size = 0;                  \
+		HFI_U32 vpss_lb_size = 0;              \
+		HFI_IRIS3_VP9D_LB_SIZE(_lb_size, frame_width, frame_height,\
+			num_vpp_pipes);             \
+		if (is_opb) { \
+			SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \
+			num_vpp_pipes); \
+		} \
+		_size = _lb_size + vpss_lb_size; \
+	} while (0)
+
+#define VPX_DECODER_FRAME_CONCURENCY_LVL (2)
+#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO (1 / 2)
+#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO (3 / 2)
+
+#define HFI_BUFFER_BIN_VP9D(_size, frame_width, frame_height, \
+				is_interlaced, num_vpp_pipes) \
+	do { \
+		HFI_U32 _size_yuv = HFI_ALIGN(frame_width, \
+		BUFFER_ALIGNMENT_16_BYTES) *\
+		HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES) * 3 / 2;  \
+		if (!is_interlaced) { \
+			_size = HFI_ALIGN(((MAX(_size_yuv, \
+			((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \
+			VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO * \
+			VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \
+			VENUS_DMA_ALIGNMENT) + HFI_ALIGN(((MAX(_size_yuv, \
+			((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \
+			VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO * \
+			VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \
+			VENUS_DMA_ALIGNMENT);  \
+			_size = _size * num_vpp_pipes;   \
+		}              \
+		else \
+			_size = 0;     \
+	} while (0)
+
+#define VP9_NUM_FRAME_INFO_BUF 32
+#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4)
+#define VP9_PROB_TABLE_SIZE (3840)
+#define VP9_FRAME_INFO_BUF_SIZE (6144)
+
+#define VP9_UDC_HEADER_BUF_SIZE (3 * 128)
+#define MAX_SUPERFRAME_HEADER_LEN (34)
+#define CCE_TILE_OFFSET_SIZE HFI_ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES)
+
+#define HFI_BUFFER_PERSIST_VP9D(_size) \
+	(_size = HFI_ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, \
+	VENUS_DMA_ALIGNMENT) + HFI_ALIGN(HFI_IRIS3_VP9D_COMV_SIZE, \
+	VENUS_DMA_ALIGNMENT) + HFI_ALIGN(MAX_SUPERFRAME_HEADER_LEN, \
+	VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_UDC_HEADER_BUF_SIZE, \
+	VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * \
+	CCE_TILE_OFFSET_SIZE, VENUS_DMA_ALIGNMENT) + \
+	HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, \
+	VENUS_DMA_ALIGNMENT) + HDR10_HIST_EXTRADATA_SIZE)
+
+#define HFI_BUFFER_LINE_MP2D(_size, frame_width, frame_height, \
+_yuv_bufcount_min, is_opb, num_vpp_pipes)           \
+	do { \
+		HFI_U32 vpss_lb_size = 0;     \
+		_size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \
+		frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+		HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\
+		VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \
+		HFI_ALIGN(SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height),\
+		VENUS_DMA_ALIGNMENT) + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL\
+		(frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \
+		2 * HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width,\
+		frame_height), VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height),\
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT) + \
+		HFI_ALIGN(SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height), \
+		VENUS_DMA_ALIGNMENT); \
+		if (is_opb) { \
+			SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \
+						num_vpp_pipes); \
+		} \
+		_size += vpss_lb_size; \
+	} while (0)
+
+#define HFI_BUFFER_BIN_MP2D(_size, frame_width, frame_height, is_interlaced) 0
+
+#define QMATRIX_SIZE (sizeof(HFI_U32) * 128 + 256)
+#define MP2D_QPDUMP_SIZE 115200
+#define HFI_BUFFER_PERSIST_MP2D(_size) \
+	do { \
+		_size = QMATRIX_SIZE + MP2D_QPDUMP_SIZE \
+	} while (0)
+
+#define HFI_BUFFER_BITSTREAM_ENC(size, frame_width, frame_height, \
+			rc_type, is_ten_bit) \
+	do { \
+		HFI_U32 aligned_width, aligned_height, bitstream_size, yuv_size; \
+		aligned_width = HFI_ALIGN(frame_width, 32); \
+		aligned_height = HFI_ALIGN(frame_height, 32); \
+		bitstream_size = aligned_width * aligned_height * 3; \
+		yuv_size = (aligned_width * aligned_height * 3) >> 1; \
+		if (aligned_width * aligned_height > (4096 * 2176)) { \
+		    /* bitstream_size = 0.25 * yuv_size; */ \
+			bitstream_size = (bitstream_size >> 3); \
+		} \
+		else if (aligned_width * aligned_height > (1280 * 720)) { \
+		    /* bitstream_size = 0.5 * yuv_size; */ \
+			bitstream_size = (bitstream_size >> 2); \
+		} else { \
+		    /* bitstream_size = 2 * yuv_size; */ \
+		} \
+		if ((rc_type == HFI_RC_CQ || rc_type == HFI_RC_OFF) && \
+			bitstream_size < yuv_size)  { \
+			bitstream_size = (bitstream_size << 1);\
+		} \
+		if (is_ten_bit) { \
+			bitstream_size = (bitstream_size) + \
+					(bitstream_size >> 2); \
+		} \
+		size = HFI_ALIGN(bitstream_size, HFI_ALIGNMENT_4096); \
+	} while (0)
+
+#define HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \
+				frame_width_coded, codec_standard) \
+	do { \
+		HFI_U32 without_tile_enc_width; \
+		HFI_U32 min_tile_size = 352, fixed_tile_width = 960; \
+		without_tile_enc_width = min_tile_size + fixed_tile_width; \
+		if (codec_standard == HFI_CODEC_ENCODE_HEVC && \
+			frame_width_coded > without_tile_enc_width) { \
+			tile_size = fixed_tile_width; \
+			tile_count = (frame_width_coded + tile_size - 1) / tile_size; \
+			last_tile_size = (frame_width_coded - (tile_size * (tile_count - 1))); \
+			if (last_tile_size < min_tile_size) { \
+				tile_count -= 1; \
+				last_tile_size = (tile_size + min_tile_size); \
+			} \
+		} else { \
+			tile_size = frame_width_coded; \
+			tile_count = 1; \
+			last_tile_size = 0; \
+		} \
+	} while (0)
+
+#define HFI_IRIS3_ENC_MB_BASED_MULTI_SLICE_COUNT(total_slice_count, frame_width, frame_height, \
+			codec_standard, multi_slice_max_mb_count) \
+	do { \
+		HFI_U32 tile_size, tile_count, last_tile_size, \
+			slice_count_per_tile, slice_count_in_last_tile; \
+		HFI_U32 mbs_in_one_tile, mbs_in_last_tile; \
+		HFI_U32 frame_width_coded, frame_height_coded, lcu_size; \
+		lcu_size = (codec_standard == HFI_CODEC_ENCODE_HEVC) ? 32 : 16; \
+		frame_width_coded = HFI_ALIGN(frame_width, lcu_size); \
+		frame_height_coded = HFI_ALIGN(frame_height, lcu_size); \
+		HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \
+			frame_width_coded, codec_standard); \
+		mbs_in_one_tile = (tile_size * frame_height_coded) / (lcu_size * lcu_size); \
+		slice_count_per_tile = \
+			(mbs_in_one_tile + multi_slice_max_mb_count - 1) / \
+			(multi_slice_max_mb_count); \
+		if (last_tile_size) { \
+			mbs_in_last_tile = \
+				(last_tile_size * frame_height_coded) / (lcu_size * lcu_size); \
+			slice_count_in_last_tile = \
+				(mbs_in_last_tile + multi_slice_max_mb_count - 1) / \
+				(multi_slice_max_mb_count); \
+			total_slice_count = \
+				(slice_count_per_tile * (tile_count - 1)) + \
+				slice_count_in_last_tile; \
+		} else \
+			total_slice_count = (slice_count_per_tile * tile_count); \
+	} while (0)
+
+#define SIZE_ROI_METADATA_ENC(size_roi, frame_width, frame_height, lcu_size)\
+	do { \
+		HFI_U32 width_in_lcus = 0, height_in_lcus = 0, n_shift = 0;    \
+		while (lcu_size && !(lcu_size & 0x1)) { \
+			n_shift++;                          \
+			lcu_size = lcu_size >> 1;          \
+		}                                      \
+		width_in_lcus = (frame_width + (lcu_size - 1)) >> n_shift; \
+		height_in_lcus = (frame_height + (lcu_size - 1)) >> n_shift;  \
+		size_roi = (((width_in_lcus + 7) >> 3) << 3) * \
+					height_in_lcus * 2 + 256; \
+	} while (0)
+
+#define HFI_BUFFER_INPUT_METADATA_ENC(size, frame_width, frame_height, \
+				is_roi_enabled, lcu_size) \
+	do { \
+		HFI_U32 roi_size = 0; \
+		if (is_roi_enabled) { \
+			SIZE_ROI_METADATA_ENC(roi_size, frame_width, \
+				frame_height, lcu_size); \
+		} \
+		size = roi_size + 16384; \
+		size = HFI_ALIGN(size, HFI_ALIGNMENT_4096); \
+	} while (0)
+
+#define HFI_BUFFER_INPUT_METADATA_H264E(size_metadata, frame_width, \
+		frame_height, is_roi_enabled)    \
+		HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \
+			frame_height, is_roi_enabled, 16)
+
+#define HFI_BUFFER_INPUT_METADATA_H265E(size_metadata, frame_width, \
+		frame_height, is_roi_enabled)    \
+		HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \
+			frame_height, is_roi_enabled, 32)
+
+#define HFI_BUFFER_ARP_ENC(size) \
+	(size = 204800)
+
+#define HFI_MAX_COL_FRAME 6
+#define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) // bytes
+#define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512
+#define HFI_VENUS_VPPSG_MAX_REGISTERS 2048
+#define HFI_VENUS_WIDTH_ALIGNMENT 128
+#define HFI_VENUS_WIDTH_TEN_BIT_ALIGNMENT 192
+#define HFI_VENUS_HEIGHT_ALIGNMENT 32
+#define VENUS_METADATA_STRIDE_MULTIPLE 64
+#define VENUS_METADATA_HEIGHT_MULTIPLE 16
+
+#ifndef SYSTEM_LAL_TILE10
+#define SYSTEM_LAL_TILE10 192
+#endif
+
+#define HFI_IRIS3_ENC_RECON_BUF_COUNT(num_recon, n_bframe, ltr_count, \
+	_total_hp_layers, _total_hb_layers, hybrid_hp, codec_standard) \
+	do { \
+		HFI_U32 num_ref = 1; \
+		if (n_bframe) \
+			num_ref = 2; \
+		if (_total_hp_layers > 1) { \
+			if (hybrid_hp) \
+				num_ref = (_total_hp_layers + 1) >> 1; \
+			else if (codec_standard == HFI_CODEC_ENCODE_HEVC) \
+				num_ref = (_total_hp_layers + 1) >> 1; \
+			else if (codec_standard == HFI_CODEC_ENCODE_AVC && \
+				_total_hp_layers < 4) \
+				num_ref = (_total_hp_layers - 1);  \
+			else \
+				num_ref = _total_hp_layers; \
+		} \
+		if (ltr_count) \
+			num_ref = num_ref + ltr_count; \
+		if (_total_hb_layers > 1) { \
+			if (codec_standard == HFI_CODEC_ENCODE_HEVC) \
+				num_ref = (_total_hb_layers); \
+			else if (codec_standard == HFI_CODEC_ENCODE_AVC) \
+				num_ref = (1 << (_total_hb_layers - 2)) + 1; \
+		} \
+		num_recon = num_ref + 1; \
+	} while (0)
+
+#define SIZE_BIN_BITSTREAM_ENC(_size, rc_type, frame_width, frame_height, \
+		work_mode, lcu_size, profile) \
+	do { \
+		HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \
+		HFI_U32 bitstream_size_eval = 0; \
+		size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \
+		size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \
+		if (work_mode == HFI_WORKMODE_2) { \
+			if (rc_type == HFI_RC_CQ || rc_type == HFI_RC_OFF) { \
+				bitstream_size_eval = (((size_aligned_width) * \
+							(size_aligned_height) * 3) >> 1); \
+			} \
+			else { \
+				bitstream_size_eval = ((size_aligned_width) * \
+							(size_aligned_height) * 3); \
+				if (rc_type == HFI_RC_LOSSLESS) { \
+					bitstream_size_eval = (bitstream_size_eval * 3 >> 2); \
+				} else if ((size_aligned_width * size_aligned_height) > \
+					(4096 * 2176)) { \
+					bitstream_size_eval >>= 3; \
+				} else if ((size_aligned_width * size_aligned_height) > \
+					(480 * 320)) { \
+					bitstream_size_eval >>= 2; \
+				} \
+				if (profile == HFI_H265_PROFILE_MAIN_10 || \
+					profile == HFI_H265_PROFILE_MAIN_10_STILL_PICTURE) \
+					bitstream_size_eval = (bitstream_size_eval * 5 >> 2); \
+			} \
+		} else { \
+			bitstream_size_eval = size_aligned_width * \
+					size_aligned_height * 3; \
+		} \
+		_size = HFI_ALIGN(bitstream_size_eval, VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define SIZE_ENC_SINGLE_PIPE(size, rc_type, bitbin_size, num_vpp_pipes, \
+			frame_width, frame_height, lcu_size) \
+	do { \
+		HFI_U32 size_single_pipe_eval = 0, sao_bin_buffer_size = 0, \
+			_padded_bin_sz = 0; \
+		HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \
+		size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \
+		size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \
+		if ((size_aligned_width * size_aligned_height) > \
+			(3840 * 2160)) { \
+			size_single_pipe_eval = (bitbin_size / num_vpp_pipes); \
+		} else if (num_vpp_pipes > 2) { \
+			size_single_pipe_eval = bitbin_size / 2; \
+		} else { \
+			size_single_pipe_eval = bitbin_size; \
+		} \
+		if (rc_type == HFI_RC_LOSSLESS) { \
+			size_single_pipe_eval = (size_single_pipe_eval << 1); \
+		} \
+		sao_bin_buffer_size = (64 * ((((frame_width) + \
+				BUFFER_ALIGNMENT_32_BYTES) * ((frame_height) +\
+				BUFFER_ALIGNMENT_32_BYTES)) >> 10)) + 384; \
+		_padded_bin_sz = HFI_ALIGN(size_single_pipe_eval, \
+				VENUS_DMA_ALIGNMENT);\
+		size_single_pipe_eval = sao_bin_buffer_size + _padded_bin_sz; \
+		size_single_pipe_eval = HFI_ALIGN(size_single_pipe_eval, \
+				VENUS_DMA_ALIGNMENT); \
+		size = size_single_pipe_eval; \
+	} while (0)
+
+#define HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, lcu_size, \
+				work_mode, num_vpp_pipes, profile)           \
+	do { \
+		HFI_U32 bitstream_size = 0, total_bitbin_buffers = 0, \
+			size_single_pipe = 0, bitbin_size = 0; \
+		SIZE_BIN_BITSTREAM_ENC(bitstream_size, rc_type, frame_width, \
+			frame_height, work_mode, lcu_size, profile);         \
+		if (work_mode == HFI_WORKMODE_2) { \
+			total_bitbin_buffers = 3; \
+			bitbin_size = bitstream_size * 12 / 10; \
+			bitbin_size = HFI_ALIGN(bitbin_size, \
+				VENUS_DMA_ALIGNMENT); \
+		} \
+		else if ((lcu_size == 16) || (num_vpp_pipes > 1)) { \
+			total_bitbin_buffers = 1; \
+			bitbin_size = bitstream_size; \
+		} \
+		if (total_bitbin_buffers > 0) { \
+			SIZE_ENC_SINGLE_PIPE(size_single_pipe, rc_type, bitbin_size, \
+				num_vpp_pipes, frame_width, frame_height, lcu_size); \
+			bitbin_size = size_single_pipe * num_vpp_pipes; \
+			_size = HFI_ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT) * \
+					total_bitbin_buffers + 512; \
+		} else \
+			/* Avoid 512 Bytes allocation in case of 1Pipe HEVC Direct Mode*/ \
+			_size = 0; \
+	} while (0)
+
+#define HFI_BUFFER_BIN_H264E(_size, rc_type, frame_width, frame_height, \
+				work_mode, num_vpp_pipes, profile)    \
+		HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 16, \
+				work_mode, num_vpp_pipes, profile)
+
+#define HFI_BUFFER_BIN_H265E(_size, rc_type, frame_width, frame_height, \
+				work_mode, num_vpp_pipes, profile)    \
+		HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 32,\
+				work_mode, num_vpp_pipes, profile)
+
+#define SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) HFI_ALIGN((256 + \
+		(num_lcu_in_frame << 4)), VENUS_DMA_ALIGNMENT)
+#define SIZE_LINE_BUF_CTRL(frame_width_coded) \
+		HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT)
+#define SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) \
+		HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT)
+
+#define SIZE_LINEBUFF_DATA(_size, is_ten_bit, frame_width_coded) \
+		(_size = is_ten_bit ? (((((10 * (frame_width_coded) +\
+		 1024) + (VENUS_DMA_ALIGNMENT - 1)) & \
+		 (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \
+		(((((10 * (frame_width_coded) + 1024) >> 1) + \
+		(VENUS_DMA_ALIGNMENT - 1)) & (~(VENUS_DMA_ALIGNMENT - 1))) * \
+		2)) : (((((8 * (frame_width_coded) + 1024) + \
+		(VENUS_DMA_ALIGNMENT - 1)) \
+		& (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \
+		(((((8 * (frame_width_coded) +\
+		1024) >> 1) + (VENUS_DMA_ALIGNMENT - 1)) & \
+		(~(VENUS_DMA_ALIGNMENT - 1))) * 2)))
+
+#define SIZE_LEFT_LINEBUFF_CTRL(_size, standard, frame_height_coded, \
+				num_vpp_pipes_enc) \
+	do { \
+		_size = (standard == HFI_CODEC_ENCODE_HEVC) ? \
+			(((frame_height_coded) + \
+			(BUF_SIZE_ALIGN_32)) / BUF_SIZE_ALIGN_32 * 4 * 16) : \
+			(((frame_height_coded) + 15) / 16 * 5 * 16); \
+		if ((num_vpp_pipes_enc) > 1) { \
+			_size += BUFFER_ALIGNMENT_512_BYTES; \
+			_size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) *\
+				(num_vpp_pipes_enc); \
+		} \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define SIZE_LEFT_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_height_coded, \
+				num_vpp_pipes_enc) \
+		(_size = (((is_ten_bit + 1) * 2 * (frame_height_coded) + \
+		VENUS_DMA_ALIGNMENT) + \
+		(VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \
+		(~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1)
+
+#define SIZE_TOP_LINEBUFF_CTRL_FE(_size, frame_width_coded, standard) \
+	do { \
+		_size = (standard == HFI_CODEC_ENCODE_HEVC) ? (64 * \
+		((frame_width_coded) >> 5)) : (VENUS_DMA_ALIGNMENT + 16 * \
+		((frame_width_coded) >> 4)); \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+	} while (0)
+
+#define SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, num_vpp_pipes_enc) \
+	((((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) >> 4)) +         \
+	   (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) &          \
+	  (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1) *  \
+	 num_vpp_pipes_enc)
+
+#define SIZE_LEFT_LINEBUFF_METADATA_RECON_Y(_size, frame_height_coded, \
+		is_ten_bit, num_vpp_pipes_enc) \
+	do { \
+		_size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \
+		(8 * (is_ten_bit ? 4 : 8)))));   \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+		_size = (_size * num_vpp_pipes_enc); \
+	} while (0)
+
+#define SIZE_LEFT_LINEBUFF_METADATA_RECON_UV(_size, frame_height_coded, \
+			is_ten_bit, num_vpp_pipes_enc) \
+	do { \
+		_size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \
+				(4 * (is_ten_bit ? 4 : 8)))));    \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \
+		_size = (_size * num_vpp_pipes_enc); \
+	} while (0)
+
+#define SIZE_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_width_coded) \
+	do { \
+		_size = ((is_ten_bit ? 3 : 2) * (frame_width_coded));         \
+		_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT);             \
+	} while (0)
+
+#define SIZE_SLICE_CMD_BUFFER (HFI_ALIGN(20480, VENUS_DMA_ALIGNMENT))
+#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096)
+
+#define SIZE_FRAME_RC_BUF_SIZE(_size, standard, frame_height_coded, \
+			num_vpp_pipes_enc) \
+	do { \
+		_size = (standard == HFI_CODEC_ENCODE_HEVC) ? (256 + 16 * \
+			(14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : \
+			(256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); \
+		_size *= 11; \
+		if (num_vpp_pipes_enc > 1) { \
+			_size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT) * \
+					num_vpp_pipes_enc;\
+		} \
+		_size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) * \
+				HFI_MAX_COL_FRAME; \
+	} while (0)
+
+#define ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \
+		(4 * (num_lcu_in_frame))), VENUS_DMA_ALIGNMENT)
+#define ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \
+		((num_lcu_in_frame) >> 3)), VENUS_DMA_ALIGNMENT)
+#define SIZE_LINE_BUF_SDE(frame_width_coded) HFI_ALIGN((256 + \
+		(16 * ((frame_width_coded) >> 4))), VENUS_DMA_ALIGNMENT)
+
+#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3)
+
+#define SIZE_LAMBDA_LUT (256 * 11)
+#define SIZE_OVERRIDE_BUF(num_lcumb) (HFI_ALIGN(((16 * (((num_lcumb) + 7)\
+		>> 3))), VENUS_DMA_ALIGNMENT) * 2)
+#define SIZE_IR_BUF(num_lcu_in_frame) HFI_ALIGN((((((num_lcu_in_frame) << 1) + 7) &\
+	(~7)) * 3), VENUS_DMA_ALIGNMENT)
+
+#define SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \
+			frame_width_coded) \
+	(HFI_ALIGN(((((((8192) >> 2) << 5) * (num_vpp_pipes_enc)) + 64) + \
+	(((((MAX((frame_width_coded), (frame_height_coded)) + 3) >> 2) << 5) +\
+	256) * 16)), VENUS_DMA_ALIGNMENT))
+
+#define SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded) \
+	HFI_ALIGN((16 * ((frame_width_coded) >> 5)), VENUS_DMA_ALIGNMENT)
+
+#define HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, is_ten_bit, \
+			num_vpp_pipes_enc, lcu_size, standard) \
+	do { \
+		HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \
+			frame_width_coded = 0, frame_height_coded = 0; \
+		HFI_U32 line_buff_data_size = 0, left_line_buff_ctrl_size = 0, \
+			left_line_buff_recon_pix_size = 0, \
+			top_line_buff_ctrl_fe_size = 0; \
+		HFI_U32 left_line_buff_metadata_recon__y__size = 0, \
+			left_line_buff_metadata_recon__uv__size = 0, \
+			line_buff_recon_pix_size = 0;          \
+		width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); \
+		height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); \
+		frame_width_coded = width_in_lcus * (lcu_size); \
+		frame_height_coded = height_in_lcus * (lcu_size); \
+		SIZE_LINEBUFF_DATA(line_buff_data_size, is_ten_bit, \
+			frame_width_coded);\
+		SIZE_LEFT_LINEBUFF_CTRL(left_line_buff_ctrl_size, standard, \
+			frame_height_coded, num_vpp_pipes_enc); \
+		SIZE_LEFT_LINEBUFF_RECON_PIX(left_line_buff_recon_pix_size, \
+			is_ten_bit, frame_height_coded, num_vpp_pipes_enc); \
+		SIZE_TOP_LINEBUFF_CTRL_FE(top_line_buff_ctrl_fe_size, \
+			frame_width_coded, standard); \
+		SIZE_LEFT_LINEBUFF_METADATA_RECON_Y\
+			(left_line_buff_metadata_recon__y__size, \
+			frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \
+		SIZE_LEFT_LINEBUFF_METADATA_RECON_UV\
+			(left_line_buff_metadata_recon__uv__size, \
+			frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \
+		SIZE_LINEBUFF_RECON_PIX(line_buff_recon_pix_size, is_ten_bit,\
+			frame_width_coded); \
+		_size = SIZE_LINE_BUF_CTRL(frame_width_coded) + \
+			SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) + \
+			line_buff_data_size + \
+			left_line_buff_ctrl_size + \
+			left_line_buff_recon_pix_size + \
+			top_line_buff_ctrl_fe_size + \
+			left_line_buff_metadata_recon__y__size + \
+			left_line_buff_metadata_recon__uv__size + \
+			line_buff_recon_pix_size + \
+		SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, \
+			num_vpp_pipes_enc) + SIZE_LINE_BUF_SDE(frame_width_coded) + \
+		SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \
+			frame_width_coded) + \
+		SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded); \
+	} while (0)
+
+#define HFI_BUFFER_LINE_H264E(_size, frame_width, frame_height, is_ten_bit, \
+		num_vpp_pipes)                   \
+		HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, 0, \
+			num_vpp_pipes, 16, HFI_CODEC_ENCODE_AVC)
+
+#define HFI_BUFFER_LINE_H265E(_size, frame_width, frame_height, is_ten_bit, \
+			num_vpp_pipes)                          \
+		HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, \
+		is_ten_bit, num_vpp_pipes, 32, HFI_CODEC_ENCODE_HEVC)
+
+#define HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, lcu_size, \
+			num_recon, standard) \
+	do { \
+		HFI_U32 size_colloc_mv = 0, size_colloc_rc = 0; \
+		HFI_U32 mb_width = ((frame_width) + 15) >> 4; \
+		HFI_U32 mb_height = ((frame_height) + 15) >> 4; \
+		HFI_U32 width_in_lcus = ((frame_width) + (lcu_size) - 1) /\
+					(lcu_size); \
+		HFI_U32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / \
+					(lcu_size); \
+		HFI_U32 num_lcu_in_frame = width_in_lcus * height_in_lcus; \
+		size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? \
+		(16 * ((num_lcu_in_frame << 2) + BUFFER_ALIGNMENT_32_BYTES)) : \
+		(3 * 16 * (width_in_lcus * height_in_lcus +\
+		BUFFER_ALIGNMENT_32_BYTES)); \
+		size_colloc_mv = HFI_ALIGN(size_colloc_mv, \
+		VENUS_DMA_ALIGNMENT) * num_recon; \
+		size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); \
+		size_colloc_rc = HFI_ALIGN(size_colloc_rc, \
+		VENUS_DMA_ALIGNMENT) * HFI_MAX_COL_FRAME; \
+		_size = size_colloc_mv + size_colloc_rc; \
+	} while (0)
+
+#define HFI_BUFFER_COMV_H264E(_size, frame_width, frame_height, num_recon) \
+		HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 16, \
+			num_recon, HFI_CODEC_ENCODE_AVC)
+
+#define HFI_BUFFER_COMV_H265E(_size, frame_width, frame_height, num_recon) \
+		HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 32,\
+			num_recon, HFI_CODEC_ENCODE_HEVC)
+
+#define HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \
+			num_vpp_pipes_enc, lcu_size, standard) \
+	do { \
+		HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \
+		frame_width_coded = 0, frame_height_coded = 0, \
+		num_lcu_in_frame = 0, num_lcumb = 0; \
+		HFI_U32	frame_rc_buf_size = 0; \
+		width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); \
+		height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); \
+		num_lcu_in_frame = width_in_lcus * height_in_lcus; \
+		frame_width_coded = width_in_lcus * (lcu_size); \
+		frame_height_coded = height_in_lcus * (lcu_size); \
+		num_lcumb = (frame_height_coded / lcu_size) * \
+		((frame_width_coded + lcu_size * 8) / lcu_size); \
+		SIZE_FRAME_RC_BUF_SIZE(frame_rc_buf_size, standard, \
+		frame_height_coded, num_vpp_pipes_enc); \
+		_size = SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) + \
+			   SIZE_SLICE_CMD_BUFFER + \
+			   SIZE_SPS_PPS_SLICE_HDR + \
+			   frame_rc_buf_size + \
+			   ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) + \
+			   ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) + \
+			   SIZE_BSE_SLICE_CMD_BUF + \
+			   SIZE_LAMBDA_LUT + \
+			   SIZE_OVERRIDE_BUF(num_lcumb) + \
+			   SIZE_IR_BUF(num_lcu_in_frame); \
+	} while (0)
+
+#define HFI_BUFFER_NON_COMV_H264E(_size, frame_width, frame_height, \
+				num_vpp_pipes_enc) \
+		HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \
+				num_vpp_pipes_enc, 16, HFI_CODEC_ENCODE_AVC)
+
+#define HFI_BUFFER_NON_COMV_H265E(_size, frame_width, frame_height, \
+				num_vpp_pipes_enc) \
+		HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \
+			num_vpp_pipes_enc, 32, HFI_CODEC_ENCODE_HEVC)
+
+#define SIZE_ENC_REF_BUFFER(size, frame_width, frame_height) \
+	do { \
+		HFI_U32 u_buffer_width = 0, u_buffer_height = 0, \
+			u_chroma_buffer_height = 0; \
+		u_buffer_height = HFI_ALIGN(frame_height, \
+			HFI_VENUS_HEIGHT_ALIGNMENT); \
+		u_chroma_buffer_height = frame_height >> 1; \
+		u_chroma_buffer_height = HFI_ALIGN(u_chroma_buffer_height, \
+			HFI_VENUS_HEIGHT_ALIGNMENT); \
+		u_buffer_width = HFI_ALIGN(frame_width, \
+			HFI_VENUS_WIDTH_ALIGNMENT); \
+		size = (u_buffer_height + u_chroma_buffer_height) * \
+			u_buffer_width; \
+	} while (0)
+
+#define SIZE_ENC_TEN_BIT_REF_BUFFER(size, frame_width, frame_height) \
+	do { \
+		HFI_U32 ref_buf_height = 0, ref_luma_stride_in_bytes = 0, \
+		u_ref_stride = 0, luma_size = 0, ref_chrm_height_in_bytes = 0, \
+		chroma_size = 0, ref_buf_size = 0; \
+		ref_buf_height = (frame_height + \
+		(HFI_VENUS_HEIGHT_ALIGNMENT - 1)) \
+		& (~(HFI_VENUS_HEIGHT_ALIGNMENT - 1)); \
+		ref_luma_stride_in_bytes = ((frame_width + \
+		SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * \
+		SYSTEM_LAL_TILE10; \
+		u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); \
+		u_ref_stride = (u_ref_stride + (BUF_SIZE_ALIGN_128 - 1)) &\
+			(~(BUF_SIZE_ALIGN_128 - 1)); \
+		luma_size = ref_buf_height * u_ref_stride; \
+		ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + \
+			(BUF_SIZE_ALIGN_32 - 1)) & (~(BUF_SIZE_ALIGN_32 - 1)); \
+		chroma_size = u_ref_stride * ref_chrm_height_in_bytes; \
+		luma_size = (luma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \
+			(~(BUF_SIZE_ALIGN_4096 - 1)); \
+		chroma_size = (chroma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \
+			(~(BUF_SIZE_ALIGN_4096 - 1)); \
+		ref_buf_size = luma_size + chroma_size; \
+		size = ref_buf_size; \
+	} while (0)
+
+#define HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit) \
+	do { \
+		HFI_U32 metadata_stride, metadata_buf_height, meta_size_y, \
+			meta_size_c; \
+		HFI_U32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; \
+		if (!is_ten_bit) { \
+			SIZE_ENC_REF_BUFFER(ref_buf_size, frame_width, \
+				frame_height); \
+			HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \
+				(frame_width), 64, \
+				HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH); \
+			HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \
+				(frame_height), 16, \
+				HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT); \
+			HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \
+				metadata_stride, metadata_buf_height); \
+			HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \
+				metadata_stride, metadata_buf_height); \
+			_size = ref_buf_size + meta_size_y + meta_size_c; \
+		} else { \
+			SIZE_ENC_TEN_BIT_REF_BUFFER(ten_bit_ref_buf_size, \
+				frame_width, frame_height); \
+			HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \
+				frame_width, VENUS_METADATA_STRIDE_MULTIPLE, \
+			HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH); \
+			HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \
+				frame_height, VENUS_METADATA_HEIGHT_MULTIPLE, \
+			HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT); \
+			HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \
+				metadata_stride, metadata_buf_height); \
+			HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \
+				metadata_stride, metadata_buf_height); \
+			_size = ten_bit_ref_buf_size + meta_size_y + \
+				meta_size_c; \
+		} \
+	} while (0)
+
+#define HFI_BUFFER_DPB_H264E(_size, frame_width, frame_height) \
+		HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, 0)
+
+#define HFI_BUFFER_DPB_H265E(_size, frame_width, frame_height, is_ten_bit) \
+		HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit)
+
+#define HFI_BUFFER_VPSS_ENC(vpss_size, dswidth, dsheight, ds_enable, blur, is_ten_bit) \
+	do { \
+		vpss_size = 0; \
+		if (ds_enable || blur) { \
+			HFI_BUFFER_DPB_ENC(vpss_size, dswidth, dsheight, is_ten_bit); \
+		} \
+	} while (0)
+
+#define HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(numinput, totalhblayers) \
+	do { \
+		numinput = 3;                                             \
+		if (totalhblayers >= 2) { \
+			numinput = (1 << (totalhblayers - 1)) + 2;        \
+		}                                                         \
+	} while (0)
+
+#endif /* __HFI_BUFFER_IRIS3__ */
diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
new file mode 100644
index 0000000..1d44662
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __H_MSM_VIDC_BUFFER_IRIS3_H__
+#define __H_MSM_VIDC_BUFFER_IRIS3_H__
+
+#include "msm_vidc_inst.h"
+
+int msm_buffer_size_iris3(struct msm_vidc_inst *inst,
+			  enum msm_vidc_buffer_type buffer_type);
+int msm_buffer_min_count_iris3(struct msm_vidc_inst *inst,
+			       enum msm_vidc_buffer_type buffer_type);
+int msm_buffer_extra_count_iris3(struct msm_vidc_inst *inst,
+				 enum msm_vidc_buffer_type buffer_type);
+
+#endif // __H_MSM_VIDC_BUFFER_IRIS3_H__
diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
new file mode 100644
index 0000000..f9a999c
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_buffer_iris3.h"
+#include "hfi_property.h"
+#include "msm_media_info.h"
+#include "msm_vidc_buffer.h"
+#include "msm_vidc_buffer_iris3.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_platform.h"
+
+static u32 msm_vidc_decoder_bin_size_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 size = 0;
+	u32 width, height, num_vpp_pipes;
+	struct v4l2_format *f;
+	bool is_interlaced;
+	u32 vpp_delay;
+
+	core = inst->core;
+
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+	if (inst->decode_vpp_delay.enable)
+		vpp_delay = inst->decode_vpp_delay.size;
+	else
+		vpp_delay = DEFAULT_BSE_VPP_DELAY;
+	if (inst->capabilities[CODED_FRAMES].value ==
+			CODED_FRAMES_PROGRESSIVE)
+		is_interlaced = false;
+	else
+		is_interlaced = true;
+	f = &inst->fmts[INPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_BIN_H264D(size, width, height,
+				     is_interlaced, vpp_delay, num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_BIN_H265D(size, width, height,
+				     0, vpp_delay, num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_VP9)
+		HFI_BUFFER_BIN_VP9D(size, width, height,
+				    0, num_vpp_pipes);
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_decoder_comv_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	u32 width, height, num_comv, vpp_delay;
+	struct v4l2_format *f;
+
+	f = &inst->fmts[INPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	num_comv = inst->buffers.output.min_count;
+
+	msm_vidc_update_cap_value(inst, NUM_COMV, num_comv, __func__);
+
+	if (inst->decode_vpp_delay.enable)
+		vpp_delay = inst->decode_vpp_delay.size;
+	else
+		vpp_delay = DEFAULT_BSE_VPP_DELAY;
+	num_comv = max(vpp_delay + 1, num_comv);
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_COMV_H264D(size, width, height, num_comv);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_COMV_H265D(size, width, height, num_comv);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_decoder_non_comv_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	u32 width, height, num_vpp_pipes;
+	struct msm_vidc_core *core;
+	struct v4l2_format *f;
+
+	core = inst->core;
+
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+
+	f = &inst->fmts[INPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_NON_COMV_H264D(size, width, height, num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_NON_COMV_H265D(size, width, height, num_vpp_pipes);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_decoder_line_size_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 size = 0;
+	u32 width, height, out_min_count, num_vpp_pipes, vpp_delay;
+	struct v4l2_format *f;
+	bool is_opb;
+	u32 color_fmt;
+
+	core = inst->core;
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+
+	color_fmt = v4l2_colorformat_to_driver(inst,
+					       inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
+					       __func__);
+	if (is_linear_colorformat(color_fmt))
+		is_opb = true;
+	else
+		is_opb = false;
+	/*
+	 * assume worst case, since color format is unknown at this
+	 * time.
+	 */
+	is_opb = true;
+
+	if (inst->decode_vpp_delay.enable)
+		vpp_delay = inst->decode_vpp_delay.size;
+	else
+		vpp_delay = DEFAULT_BSE_VPP_DELAY;
+
+	f = &inst->fmts[INPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+	out_min_count = inst->buffers.output.min_count;
+	out_min_count = max(vpp_delay + 1, out_min_count);
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_LINE_H264D(size, width, height, is_opb,
+				      num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_LINE_H265D(size, width, height, is_opb,
+				      num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_VP9)
+		HFI_BUFFER_LINE_VP9D(size, width, height, out_min_count,
+				     is_opb, num_vpp_pipes);
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_decoder_persist_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_PERSIST_H264D(size, 0);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_PERSIST_H265D(size, 0);
+	else if (inst->codec == MSM_VIDC_VP9)
+		HFI_BUFFER_PERSIST_VP9D(size);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_decoder_dpb_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	u32 color_fmt;
+	u32 width, height;
+	struct v4l2_format *f;
+
+	color_fmt = inst->capabilities[PIX_FMTS].value;
+	if (!is_linear_colorformat(color_fmt))
+		return size;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	if (color_fmt == MSM_VIDC_FMT_NV12 ||
+	    color_fmt == MSM_VIDC_FMT_NV12C) {
+		color_fmt = MSM_VIDC_FMT_NV12C;
+		HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(size, width, height,
+						  video_y_stride_bytes(color_fmt, width),
+						  video_y_scanlines(color_fmt, height),
+						  video_uv_stride_bytes(color_fmt, width),
+						  video_uv_scanlines(color_fmt, height),
+						  video_y_meta_stride(color_fmt, width),
+						  video_y_meta_scanlines(color_fmt, height),
+						  video_uv_meta_stride(color_fmt, width),
+						  video_uv_meta_scanlines(color_fmt, height));
+	} else if (color_fmt == MSM_VIDC_FMT_P010 ||
+		color_fmt == MSM_VIDC_FMT_TP10C) {
+		color_fmt = MSM_VIDC_FMT_TP10C;
+		HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(size,
+						   video_y_stride_bytes(color_fmt, width),
+						   video_y_scanlines(color_fmt, height),
+						   video_uv_stride_bytes(color_fmt, width),
+						   video_uv_scanlines(color_fmt, height),
+						   video_y_meta_stride(color_fmt, width),
+						   video_y_meta_scanlines(color_fmt, height),
+						   video_uv_meta_stride(color_fmt, width),
+						   video_uv_meta_scanlines(color_fmt, height));
+	}
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+/* encoder internal buffers */
+static u32 msm_vidc_encoder_bin_size_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 size = 0;
+	u32 width, height, num_vpp_pipes, stage, profile;
+	struct v4l2_format *f;
+
+	core = inst->core;
+
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+	stage = inst->capabilities[STAGE].value;
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+	profile = inst->capabilities[PROFILE].value;
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_BIN_H264E(size, inst->hfi_rc_type, width,
+				     height, stage, num_vpp_pipes, profile);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_BIN_H265E(size, inst->hfi_rc_type, width,
+				     height, stage, num_vpp_pipes, profile);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_get_recon_buf_count(struct msm_vidc_inst *inst)
+{
+	u32 num_buf_recon = 0;
+	s32 n_bframe, ltr_count, hp_layers = 0, hb_layers = 0;
+	bool is_hybrid_hp = false;
+	u32 hfi_codec = 0;
+
+	n_bframe = inst->capabilities[B_FRAME].value;
+	ltr_count = inst->capabilities[LTR_COUNT].value;
+
+	if (inst->hfi_layer_type == HFI_HIER_B) {
+		hb_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1;
+	} else {
+		hp_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1;
+		if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR)
+			is_hybrid_hp = true;
+	}
+
+	if (inst->codec == MSM_VIDC_H264)
+		hfi_codec = HFI_CODEC_ENCODE_AVC;
+	else if (inst->codec == MSM_VIDC_HEVC)
+		hfi_codec = HFI_CODEC_ENCODE_HEVC;
+
+	HFI_IRIS3_ENC_RECON_BUF_COUNT(num_buf_recon, n_bframe, ltr_count,
+				      hp_layers, hb_layers, is_hybrid_hp, hfi_codec);
+
+	return num_buf_recon;
+}
+
+static u32 msm_vidc_encoder_comv_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	u32 width, height, num_recon = 0;
+	struct v4l2_format *f;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	num_recon = msm_vidc_get_recon_buf_count(inst);
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_COMV_H264E(size, width, height, num_recon);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_COMV_H265E(size, width, height, num_recon);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_non_comv_size_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 size = 0;
+	u32 width, height, num_vpp_pipes;
+	struct v4l2_format *f;
+
+	core = inst->core;
+
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_NON_COMV_H264E(size, width, height, num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_NON_COMV_H265E(size, width, height, num_vpp_pipes);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_line_size_iris3(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	u32 size = 0;
+	u32 width, height, pixfmt, num_vpp_pipes;
+	bool is_tenbit = false;
+	struct v4l2_format *f;
+
+	core = inst->core;
+	num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value;
+	pixfmt = inst->capabilities[PIX_FMTS].value;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+	is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C);
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_LINE_H264E(size, width, height, is_tenbit, num_vpp_pipes);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_LINE_H265E(size, width, height, is_tenbit, num_vpp_pipes);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_dpb_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	u32 width, height, pixfmt;
+	struct v4l2_format *f;
+	bool is_tenbit;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	pixfmt = inst->capabilities[PIX_FMTS].value;
+	is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C);
+
+	if (inst->codec == MSM_VIDC_H264)
+		HFI_BUFFER_DPB_H264E(size, width, height);
+	else if (inst->codec == MSM_VIDC_HEVC)
+		HFI_BUFFER_DPB_H265E(size, width, height, is_tenbit);
+
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_arp_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+
+	HFI_BUFFER_ARP_ENC(size);
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_vpss_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 size = 0;
+	bool ds_enable = false, is_tenbit = false;
+	u32 rotation_val = HFI_ROTATION_NONE;
+	u32 width, height, driver_colorfmt;
+	struct v4l2_format *f;
+
+	ds_enable = is_scaling_enabled(inst);
+	msm_vidc_v4l2_to_hfi_enum(inst, ROTATION, &rotation_val);
+
+	f = &inst->fmts[OUTPUT_PORT];
+	if (is_rotation_90_or_270(inst)) {
+		/*
+		 * output width and height are rotated,
+		 * so unrotate them to use as arguments to
+		 * HFI_BUFFER_VPSS_ENC.
+		 */
+		width = f->fmt.pix_mp.height;
+		height = f->fmt.pix_mp.width;
+	} else {
+		width = f->fmt.pix_mp.width;
+		height = f->fmt.pix_mp.height;
+	}
+
+	f = &inst->fmts[INPUT_PORT];
+	driver_colorfmt = v4l2_colorformat_to_driver(inst,
+						     f->fmt.pix_mp.pixelformat, __func__);
+	is_tenbit = is_10bit_colorformat(driver_colorfmt);
+
+	HFI_BUFFER_VPSS_ENC(size, width, height, ds_enable, 0, is_tenbit);
+	i_vpr_l(inst, "%s: size %d\n", __func__, size);
+	return size;
+}
+
+static u32 msm_vidc_encoder_output_size_iris3(struct msm_vidc_inst *inst)
+{
+	u32 frame_size;
+	struct v4l2_format *f;
+	bool is_ten_bit = false;
+	int bitrate_mode, frame_rc;
+	u32 hfi_rc_type = HFI_RC_VBR_CFR;
+	enum msm_vidc_codec_type codec;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__);
+	if (codec == MSM_VIDC_HEVC)
+		is_ten_bit = true;
+
+	bitrate_mode = inst->capabilities[BITRATE_MODE].value;
+	frame_rc = inst->capabilities[FRAME_RC_ENABLE].value;
+	if (!frame_rc)
+		hfi_rc_type = HFI_RC_OFF;
+	else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+		hfi_rc_type = HFI_RC_CQ;
+
+	HFI_BUFFER_BITSTREAM_ENC(frame_size, f->fmt.pix_mp.width,
+				 f->fmt.pix_mp.height, hfi_rc_type, is_ten_bit);
+
+	return frame_size;
+}
+
+struct msm_vidc_buf_type_handle {
+	enum msm_vidc_buffer_type type;
+	u32 (*handle)(struct msm_vidc_inst *inst);
+};
+
+int msm_buffer_size_iris3(struct msm_vidc_inst *inst,
+			  enum msm_vidc_buffer_type buffer_type)
+{
+	int i;
+	u32 size = 0, buf_type_handle_size = 0;
+	const struct msm_vidc_buf_type_handle *buf_type_handle_arr = NULL;
+	static const struct msm_vidc_buf_type_handle dec_buf_type_handle[] = {
+		{MSM_VIDC_BUF_INPUT,           msm_vidc_decoder_input_size              },
+		{MSM_VIDC_BUF_OUTPUT,          msm_vidc_decoder_output_size             },
+		{MSM_VIDC_BUF_BIN,             msm_vidc_decoder_bin_size_iris3          },
+		{MSM_VIDC_BUF_COMV,            msm_vidc_decoder_comv_size_iris3         },
+		{MSM_VIDC_BUF_NON_COMV,        msm_vidc_decoder_non_comv_size_iris3     },
+		{MSM_VIDC_BUF_LINE,            msm_vidc_decoder_line_size_iris3         },
+		{MSM_VIDC_BUF_PERSIST,         msm_vidc_decoder_persist_size_iris3      },
+		{MSM_VIDC_BUF_DPB,             msm_vidc_decoder_dpb_size_iris3          },
+	};
+	static const struct msm_vidc_buf_type_handle enc_buf_type_handle[] = {
+		{MSM_VIDC_BUF_INPUT,           msm_vidc_encoder_input_size              },
+		{MSM_VIDC_BUF_OUTPUT,          msm_vidc_encoder_output_size_iris3       },
+		{MSM_VIDC_BUF_BIN,             msm_vidc_encoder_bin_size_iris3          },
+		{MSM_VIDC_BUF_COMV,            msm_vidc_encoder_comv_size_iris3         },
+		{MSM_VIDC_BUF_NON_COMV,        msm_vidc_encoder_non_comv_size_iris3     },
+		{MSM_VIDC_BUF_LINE,            msm_vidc_encoder_line_size_iris3         },
+		{MSM_VIDC_BUF_DPB,             msm_vidc_encoder_dpb_size_iris3          },
+		{MSM_VIDC_BUF_ARP,             msm_vidc_encoder_arp_size_iris3          },
+		{MSM_VIDC_BUF_VPSS,            msm_vidc_encoder_vpss_size_iris3         },
+	};
+
+	if (is_decode_session(inst)) {
+		buf_type_handle_size = ARRAY_SIZE(dec_buf_type_handle);
+		buf_type_handle_arr = dec_buf_type_handle;
+	} else if (is_encode_session(inst)) {
+		buf_type_handle_size = ARRAY_SIZE(enc_buf_type_handle);
+		buf_type_handle_arr = enc_buf_type_handle;
+	}
+
+	/* handle invalid session */
+	if (!buf_type_handle_arr || !buf_type_handle_size) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return size;
+	}
+
+	/* fetch buffer size */
+	for (i = 0; i < buf_type_handle_size; i++) {
+		if (buf_type_handle_arr[i].type == buffer_type) {
+			size = buf_type_handle_arr[i].handle(inst);
+			break;
+		}
+	}
+
+	/* handle unknown buffer type */
+	if (i == buf_type_handle_size) {
+		i_vpr_e(inst, "%s: unknown buffer type %#x\n", __func__, buffer_type);
+		goto exit;
+	}
+
+	i_vpr_l(inst, "buffer_size: type: %11s,  size: %9u\n", buf_name(buffer_type), size);
+
+exit:
+	return size;
+}
+
+static int msm_vidc_input_min_count_iris3(struct msm_vidc_inst *inst)
+{
+	u32 input_min_count = 0;
+	u32 total_hb_layer = 0;
+
+	if (is_decode_session(inst)) {
+		input_min_count = MIN_DEC_INPUT_BUFFERS;
+	} else if (is_encode_session(inst)) {
+		total_hb_layer = is_hierb_type_requested(inst) ?
+			inst->capabilities[ENH_LAYER_COUNT].value + 1 : 0;
+		if (inst->codec == MSM_VIDC_H264 &&
+		    !inst->capabilities[LAYER_ENABLE].value) {
+			total_hb_layer = 0;
+		}
+		HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(input_min_count,
+						  total_hb_layer);
+	} else {
+		i_vpr_e(inst, "%s: invalid domain %d\n", __func__, inst->domain);
+		return 0;
+	}
+
+	return input_min_count;
+}
+
+static int msm_buffer_dpb_count(struct msm_vidc_inst *inst)
+{
+	int count = 0;
+
+	/* encoder dpb buffer count */
+	if (is_encode_session(inst))
+		return msm_vidc_get_recon_buf_count(inst);
+
+	/* decoder dpb buffer count */
+	if (is_split_mode_enabled(inst)) {
+		count = inst->fw_min_count ?
+			inst->fw_min_count : inst->buffers.output.min_count;
+	}
+
+	return count;
+}
+
+int msm_buffer_min_count_iris3(struct msm_vidc_inst *inst,
+			       enum msm_vidc_buffer_type buffer_type)
+{
+	int count = 0;
+
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_INPUT:
+		count = msm_vidc_input_min_count_iris3(inst);
+		break;
+	case MSM_VIDC_BUF_OUTPUT:
+		count = msm_vidc_output_min_count(inst);
+		break;
+	case MSM_VIDC_BUF_BIN:
+	case MSM_VIDC_BUF_COMV:
+	case MSM_VIDC_BUF_NON_COMV:
+	case MSM_VIDC_BUF_LINE:
+	case MSM_VIDC_BUF_PERSIST:
+	case MSM_VIDC_BUF_ARP:
+	case MSM_VIDC_BUF_VPSS:
+		count = msm_vidc_internal_buffer_count(inst, buffer_type);
+		break;
+	case MSM_VIDC_BUF_DPB:
+		count = msm_buffer_dpb_count(inst);
+		break;
+	default:
+		break;
+	}
+
+	i_vpr_l(inst, "  min_count: type: %11s, count: %9u\n", buf_name(buffer_type), count);
+	return count;
+}
+
+int msm_buffer_extra_count_iris3(struct msm_vidc_inst *inst,
+				 enum msm_vidc_buffer_type buffer_type)
+{
+	int count = 0;
+
+	switch (buffer_type) {
+	case MSM_VIDC_BUF_INPUT:
+		count = msm_vidc_input_extra_count(inst);
+		break;
+	case MSM_VIDC_BUF_OUTPUT:
+		count = msm_vidc_output_extra_count(inst);
+		break;
+	default:
+		break;
+	}
+
+	i_vpr_l(inst, "extra_count: type: %11s, count: %9u\n", buf_name(buffer_type), count);
+	return count;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 30/33] iris: variant: iris3: add helper for bus and clock calculation
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (28 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 13:23 ` [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth Vikash Garodia
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This adds the helper function to calculate the required bus
bandwidth and clock frequency for the given video usecase/s.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/variant/iris3/inc/msm_vidc_power_iris3.h  |  17 +
 .../iris/variant/iris3/src/msm_vidc_power_iris3.c  | 345 +++++++++++++++++++++
 2 files changed, 362 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c

diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
new file mode 100644
index 0000000..a6f3e54
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __H_MSM_VIDC_POWER_IRIS3_H__
+#define __H_MSM_VIDC_POWER_IRIS3_H__
+
+#include "msm_vidc_inst.h"
+#include "msm_vidc_power.h"
+
+u64 msm_vidc_calc_freq_iris3(struct msm_vidc_inst *inst, u32 data_size);
+int msm_vidc_calc_bw_iris3(struct msm_vidc_inst *inst,
+			   struct vidc_bus_vote_data *vote_data);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
new file mode 100644
index 0000000..32b549c
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_inst.h"
+#include "msm_vidc_power.h"
+#include "msm_vidc_power_iris3.h"
+#include "perf_static_model.h"
+
+static int msm_vidc_init_codec_input_freq(struct msm_vidc_inst *inst, u32 data_size,
+					  struct api_calculation_input *codec_input)
+{
+	enum msm_vidc_port_type port;
+	u32 color_fmt;
+
+	if (is_encode_session(inst)) {
+		codec_input->decoder_or_encoder = CODEC_ENCODER;
+	} else if (is_decode_session(inst)) {
+		codec_input->decoder_or_encoder = CODEC_DECODER;
+	} else {
+		d_vpr_e("%s: invalid domain %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+
+	codec_input->chipset_gen = MSM_SM8550;
+
+	if (inst->codec == MSM_VIDC_H264) {
+		codec_input->codec    = CODEC_H264;
+		codec_input->lcu_size = 16;
+		if (inst->capabilities[ENTROPY_MODE].value ==
+				V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+			codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC;
+		else
+			codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC;
+	} else if (inst->codec == MSM_VIDC_HEVC) {
+		codec_input->codec    = CODEC_HEVC;
+		codec_input->lcu_size = 32;
+	} else if (inst->codec == MSM_VIDC_VP9) {
+		codec_input->codec    = CODEC_VP9;
+		codec_input->lcu_size = 16;
+	} else {
+		d_vpr_e("%s: invalid codec %d\n", __func__, inst->codec);
+		return -EINVAL;
+	}
+
+	codec_input->pipe_num = inst->capabilities[PIPE].value;
+	codec_input->frame_rate = inst->max_rate;
+
+	port = is_decode_session(inst) ? INPUT_PORT : OUTPUT_PORT;
+	codec_input->frame_width = inst->fmts[port].fmt.pix_mp.width;
+	codec_input->frame_height = inst->fmts[port].fmt.pix_mp.height;
+
+	if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) {
+		codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S;
+	} else if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_2) {
+		codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S;
+	} else {
+		d_vpr_e("%s: invalid stage %d\n", __func__,
+			inst->capabilities[STAGE].value);
+		return -EINVAL;
+	}
+
+	if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_8)
+		codec_input->bitdepth = CODEC_BITDEPTH_8;
+	else
+		codec_input->bitdepth = CODEC_BITDEPTH_10;
+
+	/*
+	 * Used for calculating Encoder GOP Complexity
+	 * hierachical_layer= 0..7 used as Array Index
+	 * inst->capabilities[B_FRAME].value=[ 0 1 2]
+	 * TODO how to map?
+	 */
+
+	/* set as IPP */
+	codec_input->hierachical_layer = 0;
+
+	if (is_decode_session(inst))
+		color_fmt =
+			v4l2_colorformat_to_driver(inst,
+						   inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
+						   __func__);
+	else
+		color_fmt =
+			v4l2_colorformat_to_driver(inst,
+						   inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat,
+						   __func__);
+
+	codec_input->linear_opb = is_linear_colorformat(color_fmt);
+	codec_input->bitrate_mbps =
+		(codec_input->frame_rate * data_size * 8) / 1000000;
+
+	/* set as sanity mode */
+	codec_input->regression_mode = 1;
+
+	return 0;
+}
+
+static int msm_vidc_init_codec_input_bus(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d,
+					 struct api_calculation_input *codec_input)
+{
+	u32 complexity_factor_int = 0, complexity_factor_frac = 0;
+	bool opb_compression_enabled = false;
+
+	if (!d)
+		return -EINVAL;
+
+	if (d->domain == MSM_VIDC_ENCODER) {
+		codec_input->decoder_or_encoder = CODEC_ENCODER;
+	} else if (d->domain == MSM_VIDC_DECODER) {
+		codec_input->decoder_or_encoder = CODEC_DECODER;
+	} else {
+		d_vpr_e("%s: invalid domain %d\n", __func__, d->domain);
+		return -EINVAL;
+	}
+
+	codec_input->chipset_gen = MSM_SM8550;
+
+	if (d->codec == MSM_VIDC_H264) {
+		codec_input->codec = CODEC_H264;
+	} else if (d->codec == MSM_VIDC_HEVC) {
+		codec_input->codec = CODEC_HEVC;
+	} else if (d->codec == MSM_VIDC_VP9) {
+		codec_input->codec = CODEC_VP9;
+	} else {
+		d_vpr_e("%s: invalid codec %d\n", __func__, d->codec);
+		return -EINVAL;
+	}
+
+	codec_input->lcu_size = d->lcu_size;
+	codec_input->pipe_num = d->num_vpp_pipes;
+	codec_input->frame_rate = d->fps;
+	codec_input->frame_width = d->input_width;
+	codec_input->frame_height = d->input_height;
+
+	if (d->work_mode == MSM_VIDC_STAGE_1) {
+		codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S;
+	} else if (d->work_mode == MSM_VIDC_STAGE_2) {
+		codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S;
+	} else {
+		d_vpr_e("%s: invalid stage %d\n", __func__, d->work_mode);
+		return -EINVAL;
+	}
+
+	if (inst->capabilities[ENTROPY_MODE].value ==
+			V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) {
+		codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC;
+	} else if (inst->capabilities[ENTROPY_MODE].value ==
+			V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) {
+		codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC;
+	} else {
+		d_vpr_e("%s: invalid entropy %d\n", __func__,
+			inst->capabilities[ENTROPY_MODE].value);
+		return -EINVAL;
+	}
+
+	/*
+	 * Used for calculating Encoder GOP Complexity
+	 * hierachical_layer= 0..7 used as Array Index
+	 * TODO how to map?
+	 */
+	codec_input->hierachical_layer = 0; /* set as IPP */
+
+	/*
+	 * If the calculated motion_vector_complexity is > 2 then set the
+	 * complexity_setting and refframe_complexity to be pwc(performance worst case)
+	 * values. If the motion_vector_complexity is < 2 then set the complexity_setting
+	 * and refframe_complexity to be average case values.
+	 */
+
+	complexity_factor_int = Q16_INT(d->complexity_factor);
+	complexity_factor_frac = Q16_FRAC(d->complexity_factor);
+
+	if (complexity_factor_int < COMPLEXITY_THRESHOLD ||
+	    (complexity_factor_int == COMPLEXITY_THRESHOLD &&
+	     complexity_factor_frac == 0)) {
+		/* set as average case values */
+		codec_input->complexity_setting = COMPLEXITY_SETTING_AVG;
+		codec_input->refframe_complexity = REFFRAME_COMPLEXITY_AVG;
+	} else {
+		/* set as pwc */
+		codec_input->complexity_setting = COMPLEXITY_SETTING_PWC;
+		codec_input->refframe_complexity = REFFRAME_COMPLEXITY_PWC;
+	}
+
+	codec_input->status_llc_onoff = d->use_sys_cache;
+
+	if (__bpp(d->color_formats[0]) == 8)
+		codec_input->bitdepth = CODEC_BITDEPTH_8;
+	else
+		codec_input->bitdepth = CODEC_BITDEPTH_10;
+
+	if (d->num_formats == 1) {
+		codec_input->split_opb = 0;
+		codec_input->linear_opb = !__ubwc(d->color_formats[0]);
+	} else if (d->num_formats == 2) {
+		codec_input->split_opb = 1;
+		codec_input->linear_opb = !__ubwc(d->color_formats[1]);
+	} else {
+		d_vpr_e("%s: invalid num_formats %d\n",
+			__func__, d->num_formats);
+		return -EINVAL;
+	}
+
+	codec_input->linear_ipb = 0;   /* set as ubwc ipb */
+
+	/* TODO Confirm if we always LOSSLESS mode ie lossy_ipb = 0*/
+	codec_input->lossy_ipb = 0;   /* set as lossless ipb */
+
+	/* TODO Confirm if no multiref */
+	codec_input->encoder_multiref = 0;	/* set as no multiref */
+	codec_input->bitrate_mbps = (d->bitrate / 1000000); /* bps 10;	set as 10mbps */
+
+	opb_compression_enabled = d->num_formats >= 2 && __ubwc(d->color_formats[1]);
+
+	/* ANDROID CR is in Q16 format, StaticModel CR in x100 format */
+	codec_input->cr_dpb = ((Q16_INT(d->compression_ratio) * 100) +
+			       Q16_FRAC(d->compression_ratio));
+
+	codec_input->cr_opb = opb_compression_enabled ?
+		codec_input->cr_dpb : 65536;
+
+	codec_input->cr_ipb = ((Q16_INT(d->input_cr) * 100) + Q16_FRAC(d->input_cr));
+	codec_input->cr_rpb = codec_input->cr_dpb;  /* cr_rpb only for encoder */
+
+	/* disable by default, only enable for aurora depth map session */
+	codec_input->lumaonly_decode = 0;
+
+	/* set as custom regression mode, as are using cr,cf values from FW */
+	codec_input->regression_mode = REGRESSION_MODE_CUSTOM;
+
+	/* Dump all the variables for easier debugging */
+	if (msm_vidc_debug & VIDC_BUS) {
+		struct dump dump[] = {
+		{"complexity_factor_int", "%d", complexity_factor_int},
+		{"complexity_factor_frac", "%d", complexity_factor_frac},
+		{"refframe_complexity", "%d", codec_input->refframe_complexity},
+		{"complexity_setting", "%d", codec_input->complexity_setting},
+		{"cr_dpb", "%d", codec_input->cr_dpb},
+		{"cr_opb", "%d", codec_input->cr_opb},
+		{"cr_ipb", "%d", codec_input->cr_ipb},
+		{"cr_rpb", "%d", codec_input->cr_rpb},
+		{"lcu size", "%d", codec_input->lcu_size},
+		{"pipe number", "%d", codec_input->pipe_num},
+		{"frame_rate", "%d", codec_input->frame_rate},
+		{"frame_width", "%d", codec_input->frame_width},
+		{"frame_height", "%d", codec_input->frame_height},
+		{"work_mode", "%d", d->work_mode},
+		{"encoder_or_decode", "%d", inst->domain},
+		{"chipset_gen", "%d", codec_input->chipset_gen},
+		{"codec_input", "%d", codec_input->codec},
+		{"entropy_coding_mode", "%d", codec_input->entropy_coding_mode},
+		{"hierachical_layer", "%d", codec_input->hierachical_layer},
+		{"status_llc_onoff", "%d", codec_input->status_llc_onoff},
+		{"bit_depth", "%d", codec_input->bitdepth},
+		{"split_opb", "%d", codec_input->split_opb},
+		{"linear_opb", "%d", codec_input->linear_opb},
+		{"linear_ipb", "%d", codec_input->linear_ipb},
+		{"lossy_ipb", "%d", codec_input->lossy_ipb},
+		{"encoder_multiref", "%d", codec_input->encoder_multiref},
+		{"bitrate_mbps", "%d", codec_input->bitrate_mbps},
+		{"lumaonly_decode", "%d", codec_input->lumaonly_decode},
+		{"regression_mode", "%d", codec_input->regression_mode},
+		};
+		__dump(dump, ARRAY_SIZE(dump));
+	}
+
+	return 0;
+}
+
+u64 msm_vidc_calc_freq_iris3(struct msm_vidc_inst *inst, u32 data_size)
+{
+	u64 freq = 0;
+	struct msm_vidc_core *core;
+	int ret = 0;
+	struct api_calculation_input codec_input;
+	struct api_calculation_freq_output codec_output;
+	u32 fps, mbpf;
+
+	core = inst->core;
+
+	mbpf = msm_vidc_get_mbs_per_frame(inst);
+	fps = inst->max_rate;
+
+	memset(&codec_input, 0, sizeof(struct api_calculation_input));
+	memset(&codec_output, 0, sizeof(struct api_calculation_freq_output));
+	ret = msm_vidc_init_codec_input_freq(inst, data_size, &codec_input);
+	if (ret)
+		return freq;
+	ret = msm_vidc_calculate_frequency(codec_input, &codec_output);
+	if (ret)
+		return freq;
+	freq = codec_output.hw_min_freq * 1000000; /* Convert to Hz */
+
+	i_vpr_p(inst, "%s: filled len %d, required freq %llu, fps %u, mbpf %u\n",
+		__func__, data_size, freq, fps, mbpf);
+
+	if (inst->iframe && is_hevc_10bit_decode_session(inst)) {
+		/*
+		 * for HEVC 10bit and iframe case only allow TURBO and
+		 * limit to NOM for all other cases
+		 */
+	} else {
+		/* limit to NOM, index 0 is TURBO, index 1 is NOM clock rate */
+		if (core->resource->freq_set.count >= 2 &&
+		    freq > core->resource->freq_set.freq_tbl[1].freq)
+			freq = core->resource->freq_set.freq_tbl[1].freq;
+	}
+
+	return freq;
+}
+
+int msm_vidc_calc_bw_iris3(struct msm_vidc_inst *inst,
+			   struct vidc_bus_vote_data *vidc_data)
+{
+	int ret = 0;
+	struct api_calculation_input codec_input;
+	struct api_calculation_bw_output codec_output;
+
+	if (!vidc_data)
+		return ret;
+
+	memset(&codec_input, 0, sizeof(struct api_calculation_input));
+	memset(&codec_output, 0, sizeof(struct api_calculation_bw_output));
+
+	ret = msm_vidc_init_codec_input_bus(inst, vidc_data, &codec_input);
+	if (ret)
+		return ret;
+	ret = msm_vidc_calculate_bandwidth(codec_input, &codec_output);
+	if (ret)
+		return ret;
+
+	vidc_data->calc_bw_ddr = kbps(codec_output.ddr_bw_rd + codec_output.ddr_bw_wr);
+	vidc_data->calc_bw_llcc = kbps(codec_output.noc_bw_rd + codec_output.noc_bw_wr);
+
+	i_vpr_l(inst, "%s: calc_bw_ddr %llu calc_bw_llcc %llu",
+		__func__, vidc_data->calc_bw_ddr, vidc_data->calc_bw_llcc);
+
+	return ret;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (29 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 30/33] iris: variant: iris3: add helper for bus and clock calculation Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 18:09   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency Vikash Garodia
                   ` (4 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements the logic to compute bus bandwidth required by encoder
or decoder for a specific usecase. It takes input as various video
usecase parameters as configured by clients.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/variant/iris3/inc/perf_static_model.h     | 229 ++++++
 .../iris/variant/iris3/src/msm_vidc_bus_iris3.c    | 884 +++++++++++++++++++++
 2 files changed, 1113 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c

diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
new file mode 100644
index 0000000..238f1af
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _PERF_STATIC_MODEL_H_
+#define _PERF_STATIC_MODEL_H_
+
+#include <linux/types.h>
+
+/* Reordered CODECS to match Bitrate Table rows */
+#define CODEC_H264_CAVLC                        0
+#define CODEC_H264                              1
+#define CODEC_HEVC                              2
+#define CODEC_VP9                               3
+
+#define CODEC_BSE_FrameFactor                   0
+#define CODEC_BSE_MBFactor                      1
+#define CODEC_BSE_LUC_SIZE                      2
+
+#define CODEC_GOP_IPP                           0
+#define CODEC_GOP_IbP                           1
+#define CODEC_GOP_I1B2b1P                       2
+#define CODEC_GOP_I3B4b1P                       3
+#define CODEC_GOP_PONLY                         4
+#define CODEC_GOP_BONLY                         6
+#define CODEC_GOP_IONLY                         7
+
+#define CODEC_ENCODER_GOP_Bb_ENTRY              0
+#define CODEC_ENCODER_GOP_P_ENTRY               1
+#define CODEC_ENCODER_GOP_FACTORY_ENTRY         2
+
+#define CODEC_ENTROPY_CODING_CAVLC              0
+#define CODEC_ENTROPY_CODING_CABAC              1
+
+#define CODEC_VSPVPP_MODE_1S                    1
+#define CODEC_VSPVPP_MODE_2S                    2
+
+#define COMP_SETTING_PWC                        0
+#define COMP_SETTING_AVG                        1
+#define COMP_SETTING_POWER                      2
+
+#define CODEC_BITDEPTH_8                        8
+#define CODEC_BITDEPTH_10                       10
+
+#define ENCODE_YUV                              0
+#define ENCODE_RGB                              1
+
+#define COMPLEXITY_PWC                          0
+#define COMPLEXITY_AVG                          1
+#define COMPLEXITY_POWER                        2
+
+#define MAX_LINE                                2048
+#ifndef VENUS_MAX_FILENAME_LENGTH
+#define VENUS_MAX_FILENAME_LENGTH               1024
+#endif
+
+#define CODEC_ENCODER                           1
+#define CODEC_DECODER                           2
+
+#define COMPLEXITY_THRESHOLD                    2
+
+enum chipset_generation {
+	MSM_SM8450,
+	MSM_SM8550,
+	MSM_MAX,
+};
+
+enum regression_mode {
+	/* ignores client set cr and bitrate settings */
+	REGRESSION_MODE_SANITY = 1,
+	/* cr and bitrate default mode */
+	REGRESSION_MODE_DEFAULT,
+	/* custom mode where client will set cr and bitrate values */
+	REGRESSION_MODE_CUSTOM,
+};
+
+/*
+ * If firmware provided motion_vector_complexity is >= 2 then set the
+ * complexity_setting as PWC (performance worst case)
+ * If the motion_vector_complexity is < 2 then set the complexity_setting
+ * as AVG (average case value)
+ */
+enum complexity_setting {
+	COMPLEXITY_SETTING_PWC = 0,
+	COMPLEXITY_SETTING_AVG = 1,
+	COMPLEXITY_SETTING_PWR = 2,
+};
+
+/*
+ * If firmware provided motion_vector_complexity is >= 2 then set the
+ * refframe_complexity as PWC (performance worst case)
+ * If the motion_vector_complexity is < 2 then set the refframe_complexity
+ * as AVG (average case value)
+ */
+enum refframe_complexity {
+	REFFRAME_COMPLEXITY_PWC = 4,
+	REFFRAME_COMPLEXITY_AVG = 2,
+	REFFRAME_COMPLEXITY_PWR = 1,
+};
+
+struct api_calculation_input {
+	/*2: decoder; 1: encoder */
+	u32 decoder_or_encoder;
+
+	/* enum chipset_generation */
+	u32 chipset_gen;
+
+	u32 codec;
+	u32 lcu_size;
+	u32 pipe_num;
+	u32 frame_rate;
+	u32 frame_width;
+	u32 frame_height;
+	u32 vsp_vpp_mode;
+	u32 entropy_coding_mode;
+	u32 hierachical_layer;
+
+	/* PWC, AVG/POWER */
+	u32 complexity_setting;
+
+	u32 status_llc_onoff;
+	u32 bitdepth;
+	u32 linear_opb;
+
+	/* AV1D FG */
+	u32 split_opb;
+
+	u32 linear_ipb;
+	u32 lossy_ipb;
+	u32 ipb_yuvrgb;
+	u32 encoder_multiref;
+	u32 bitrate_mbps;
+	u32 refframe_complexity;
+	u32 cr_ipb;
+	u32 cr_rpb;
+	u32 cr_dpb;
+	u32 cr_opb;
+	u32 regression_mode;
+
+	/* used in aurora for depth map decode */
+	u32 lumaonly_decode;
+};
+
+struct corner_voting {
+	u32 percent_lowbound;
+	u32 percent_highbound;
+};
+
+struct api_calculation_freq_output {
+	u32 vpp_min_freq;
+	u32 vsp_min_freq;
+	u32 tensilica_min_freq;
+	u32 hw_min_freq;
+	u32 enc_hqmode;
+	struct corner_voting usecase_corner;
+};
+
+struct api_calculation_bw_output {
+	u32 vsp_read_noc;
+	u32 vsp_write_noc;
+	u32 vsp_read_ddr;
+	u32 vsp_write_ddr;
+	u32 vsp_rd_wr_total_noc;
+	u32 vsp_rd_wr_total_ddr;
+
+	u32 collocated_rd_noc;
+	u32 collocated_wr_noc;
+	u32 collocated_rd_ddr;
+	u32 collocated_wr_ddr;
+	u32 collocated_rd_wr_total_noc;
+	u32 collocated_rd_wr_total_ddr;
+
+	u32 dpb_rd_y_noc;
+	u32 dpb_rd_crcb_noc;
+	u32 dpb_rdwr_duetooverlap_noc;
+	u32 dpb_wr_noc;
+	u32 dpb_rd_y_ddr;
+	u32 dpb_rd_crcb_ddr;
+	u32 dpb_rdwr_duetooverlap_ddr;
+	u32 dpb_wr_ddr;
+	u32 dpb_rd_wr_total_noc;
+	u32 dpb_rd_wr_total_ddr;
+
+	u32 opb_write_total_noc;
+	u32 opb_write_total_ddr;
+
+	u32 ipb_rd_total_noc;
+	u32 ipb_rd_total_ddr;
+
+	u32 bse_tlb_rd_noc;
+	u32 bse_tlb_wr_noc;
+	u32 bse_tlb_rd_ddr;
+	u32 bse_tlb_wr_ddr;
+	u32 bse_rd_wr_total_noc;
+	u32 bse_rd_wr_total_ddr;
+
+	u32 statistics_rd_noc;
+	u32 statistics_wr_noc;
+	u32 statistics_rd_ddr;
+	u32 statistics_wr_ddr;
+
+	u32 mmu_rd_noc;
+	u32 mmu_rd_ddr;
+
+	u32 noc_bw_rd;
+	u32 noc_bw_wr;
+	u32 ddr_bw_rd;
+	u32 ddr_bw_wr;
+
+	/* llc BW components for aurora */
+	u32 dpb_rd_y_llc;
+	u32 dpb_rd_crcb_llc;
+	u32 dpb_wr_llc;
+	u32 bse_tlb_rd_llc;
+	u32 bse_tlb_wr_llc;
+	u32 vsp_read_llc;
+	u32 vsp_write_llc;
+
+	u32 llc_bw_rd;
+	u32 llc_bw_wr;
+};
+
+int msm_vidc_calculate_frequency(struct api_calculation_input codec_input,
+				 struct api_calculation_freq_output *codec_output);
+int msm_vidc_calculate_bandwidth(struct api_calculation_input codec_input,
+				 struct api_calculation_bw_output *codec_output);
+
+#endif /*_PERF_STATIC_MODEL_H_ */
diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
new file mode 100644
index 0000000..92aa995
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
@@ -0,0 +1,884 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_debug.h"
+#include "perf_static_model.h"
+
+/* 100x */
+static u32 dpbopb_ubwc30_cr_table_cratio_iris3[7][12] = {
+	{237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152},
+	{269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149},
+	{269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149},
+	{269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149},
+	{237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152},
+	{269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149},
+	{269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149},
+};
+
+/* 100x */
+static u32 rpb_ubwc30_cr_table_cratio_iris3[7][12] = {
+	{193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149},
+	{285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152},
+	{285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152},
+	{285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152},
+	{193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149},
+	{285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152},
+	{285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152},
+};
+
+/* 100x */
+static u32 ipblossy_ubwc30_cr_table_cratio_iris3[7][12] = {
+	{215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231},
+	{254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249},
+	{254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249},
+	{254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249},
+	{215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231},
+	{254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249},
+	{254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249},
+};
+
+/* 100x */
+static u32 ipblossless_ubwc30_cr_table_cratio_iris3[7][12] = {
+	{185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146},
+	{186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148},
+	{186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148},
+	{186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148},
+	{185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146},
+	{186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148},
+	{186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148},
+};
+
+/* 100x */
+static u32 en_original_compression_factor_rgba_pwd_iris3 = 243;
+/* 100x */
+static u32 en_original_compression_factor_rgba_avg_iris3 = 454;
+
+/*                                H   I   J         K   L   M      N   O   P
+ *         TotalW   Total R       Frequency         Write         Read
+ * Name                           B   b   P         B   b   P      B   b   P
+ * I3B4b1P    0.5    1.875        3   4   1         1   0   1      2   2   1
+ * I1B2b1P    0.5    1.75         1   2   1         1   0   1      2   2   1
+ * IbP        0.5    1.5          0   1   1         1   0   1      2   2   1
+ * IPP        1      1            0   0   1         1   0   1      2   2   1
+ * P          1      1            0   0   1         1   0   1      2   2   1
+ * smallB     0      2            0   1   0         1   0   1      2   2   1
+ * bigB       1      2            1   0   0         1   0   1      2   2   1
+ *
+ * Total W = SUMPRODUCT(H16:J16, K16 : M16) / SUM(H16:J16)
+ * Total R = SUMPRODUCT(H16:J16, N16 : P16) / SUM(H16:J16)
+ */
+
+/* 1000x */
+static u32 iris3_en_readfactor[7] = {1000, 1500, 1750, 1875, 1000, 2000, 2000};
+/* 1000x */
+static u32 iris3_en_writefactor[7] = {1000, 500, 500, 500, 1000, 0, 1000};
+static u32 iris3_en_frame_num_parallel = 1;
+
+u32 calculate_number_lcus_iris3(u32 width, u32 height, u32 lcu_size)
+{
+	u32 mbs_width = (width % lcu_size) ?
+		(width / lcu_size + 1) : (width / lcu_size);
+	u32 mbs_height = (height % lcu_size) ?
+		(height / lcu_size + 1) : (height / lcu_size);
+
+	return mbs_width * mbs_height;
+}
+
+u32 calculate_number_ubwctiles_iris3(u32 width, u32 height, u32 tile_w, u32 tile_h)
+{
+	u32 tiles_width = (width % tile_w) ?
+		(width / tile_w + 1) : (width / tile_w);
+	u32 tiles_height = (height % tile_h) ?
+		(height / tile_h + 1) : (height / tile_h);
+
+	return tiles_width * tiles_height;
+}
+
+struct compression_factors {
+	u32 dpb_cf_y;
+	u32 dpb_cf_cbcr;
+	u32 opb_cf_ycbcr;
+	u32 dpb_cr_y;
+	u32 ipb_cr_y;
+	u32 ipb_cr;
+} compression_factor;
+
+u32 get_compression_factors(struct compression_factors *compression_factor,
+			    struct api_calculation_input codec_input)
+{
+	u8 cr_index_entry, cr_index_y, cr_index_c, cr_index_uni;
+	u32 frame_width;
+	u32 frame_height;
+
+	frame_width = codec_input.frame_width;
+	frame_height = codec_input.frame_height;
+	if (frame_width * frame_height <= 1920 * 1080)
+		cr_index_entry = 0;
+	else
+		cr_index_entry = 1;
+
+	if (codec_input.bitdepth == CODEC_BITDEPTH_8) {
+		/* NOT PWC or average and power case */
+		if (codec_input.complexity_setting != 0) {
+			cr_index_y = 0;
+			cr_index_c = 1;
+			cr_index_uni = 2;
+		} else {
+			cr_index_y = 3;
+			cr_index_c = 4;
+			cr_index_uni = 5;
+		}
+	} else {
+		/* NOT PWC or average and power case */
+		if (codec_input.complexity_setting != 0) {
+			cr_index_y = 6;
+			cr_index_c = 7;
+			cr_index_uni = 8;
+		} else {
+			cr_index_y = 9;
+			cr_index_c = 10;
+			cr_index_uni = 11;
+		}
+	}
+
+	if (codec_input.decoder_or_encoder == CODEC_DECODER) {
+		compression_factor->dpb_cf_y =
+			dpbopb_ubwc30_cr_table_cratio_iris3[cr_index_entry][cr_index_y];
+		compression_factor->dpb_cf_cbcr =
+			dpbopb_ubwc30_cr_table_cratio_iris3[cr_index_entry][cr_index_c];
+		compression_factor->opb_cf_ycbcr =
+			dpbopb_ubwc30_cr_table_cratio_iris3[cr_index_entry][cr_index_uni];
+
+		if (codec_input.regression_mode == 3 &&
+		    /* input cr numbers from interface */
+		    (codec_input.cr_dpb != 0 || codec_input.cr_opb != 0)) {
+			compression_factor->dpb_cf_y = (u32)(codec_input.cr_dpb * 100);
+			compression_factor->dpb_cf_cbcr = (u32)(codec_input.cr_dpb * 100);
+			compression_factor->opb_cf_ycbcr = (u32)(codec_input.cr_opb * 100);
+		}
+	} else { /* encoder */
+		/*
+		 * IPB CR Table Choice; static sheet (if framewidth<3840, use lossless table)
+		 * (else, use lossy table)
+		 * stick to this choice for SW purpose (no change for SW)
+		 */
+		if (frame_width < 3840) {
+			compression_factor->ipb_cr =
+				ipblossless_ubwc30_cr_table_cratio_iris3
+				[cr_index_entry][cr_index_uni];
+			compression_factor->ipb_cr_y =
+				ipblossless_ubwc30_cr_table_cratio_iris3
+				[cr_index_entry][cr_index_y];
+		} else {
+			compression_factor->ipb_cr =
+				ipblossy_ubwc30_cr_table_cratio_iris3[cr_index_entry]
+				[cr_index_uni];
+			compression_factor->ipb_cr_y =
+				ipblossy_ubwc30_cr_table_cratio_iris3[cr_index_entry]
+				[cr_index_y];
+		}
+
+		compression_factor->dpb_cf_y =
+			rpb_ubwc30_cr_table_cratio_iris3[cr_index_entry][cr_index_y];
+
+		compression_factor->dpb_cf_cbcr =
+			rpb_ubwc30_cr_table_cratio_iris3[cr_index_entry][cr_index_c];
+
+		if (codec_input.regression_mode == 3 &&
+		    /* input cr from interface */
+		    (codec_input.cr_ipb != 0 || codec_input.cr_rpb != 0)) {
+			compression_factor->dpb_cf_y = (u32)(codec_input.cr_rpb * 100);
+			compression_factor->dpb_cf_cbcr = (u32)(codec_input.cr_rpb * 100);
+			compression_factor->ipb_cr_y = (u32)(codec_input.cr_ipb * 100);
+		}
+	}
+
+	return 0;
+}
+
+static int calculate_bandwidth_decoder_iris3(struct api_calculation_input codec_input,
+					     struct api_calculation_bw_output *codec_output)
+{
+	/* common control parameters */
+	u32 frame_width;
+	u32 frame_height;
+	u32 frame_lcu_size = 16; /* initialized to h264 */
+	u32 lcu_per_frame;
+	u32 target_bitrate;
+	u32 collocated_bytes_per_lcu = 16; /* initialized to h264 */
+
+	u32 frame420_y_bw_linear_8bpp;
+	u32 frame420_y_bw_no_ubwc_tile_10bpp;
+	u32 frame420_y_bw_linear_10bpp;
+
+	u16 ubwc_tile_w;
+	u16 ubwc_tile_h;
+
+	u32 dpb_compression_factor_y;
+	u32 dpb_compression_factor_cbcr;
+
+	u32 reconstructed_write_bw_factor_rd;
+	u32 reference_y_read_bw_factor;
+	u32 reference_cbcr_read_bw_factor;
+
+	/* decoder control parameters */
+	u32 decoder_vsp_read_factor = 6;
+	u32 bins_to_bits_factor = 4;
+
+	u32 dpb_to_opb_ratios_ds = 1;
+
+	u8 llc_enabled_ref_y_rd = 1;
+	u8 llc_enable_ref_crcb_rd = 1;
+	u8 llc_enabled_bse_tlb = 1;
+	/* this is for 2pipe and 1pipe LLC */
+
+	u32 opb_compression_factor_ycbcr;
+	u32 dpb_ubwc_tile_width_pixels;
+	u32 dpb_ubwc_tile_height_pixels;
+	u32 decoder_frame_complexity_factor;
+	u32 llc_saving = 130; /* Initialized to H264 */
+
+	u32 bse_tlb_byte_per_lcu = 0;
+
+	u32 large_bw_calculation_fp = 0;
+
+	llc_enabled_ref_y_rd = (codec_input.status_llc_onoff) ? 1 : 0;
+	llc_enable_ref_crcb_rd = (codec_input.status_llc_onoff) ? 1 : 0;
+	/* H265D BSE tlb in LLC will be pored in Kailua */
+	llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0;
+
+	frame_width = codec_input.frame_width;
+	frame_height = codec_input.frame_height;
+	if (codec_input.codec == CODEC_H264 ||
+	    codec_input.codec == CODEC_H264_CAVLC) {
+		frame_lcu_size = 16;
+		collocated_bytes_per_lcu = 16;
+		llc_saving = 130;
+	} else if (codec_input.codec == CODEC_HEVC) {
+		if (codec_input.lcu_size == 32) {
+			frame_lcu_size = 32;
+			collocated_bytes_per_lcu = 64;
+			llc_saving = 114;
+		} else if (codec_input.lcu_size == 64) {
+			frame_lcu_size = 64;
+			collocated_bytes_per_lcu = 256;
+			llc_saving = 107;
+		}
+	} else if (codec_input.codec == CODEC_VP9) {
+		if (codec_input.lcu_size == 32) {
+			frame_lcu_size = 32;
+			collocated_bytes_per_lcu = 64;
+			llc_saving = 114;
+		} else if (codec_input.lcu_size == 64) {
+			frame_lcu_size = 64;
+			collocated_bytes_per_lcu = 256;
+			llc_saving = 107;
+		}
+	}
+
+	lcu_per_frame =
+		calculate_number_lcus_iris3(frame_width, frame_height, frame_lcu_size);
+
+	target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */
+
+	ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48;
+	ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4;
+
+	frame420_y_bw_linear_8bpp =
+		((calculate_number_ubwctiles_iris3(frame_width, frame_height, 32, 8) *
+		256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+
+	frame420_y_bw_no_ubwc_tile_10bpp =
+		((calculate_number_ubwctiles_iris3(frame_width, frame_height, 48, 4) *
+		256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+	frame420_y_bw_linear_10bpp = ((frame_width * frame_height *
+		codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000;
+
+	/* TODO Integrate Compression Ratio returned by FW */
+	get_compression_factors(&compression_factor, codec_input);
+	dpb_compression_factor_y = compression_factor.dpb_cf_y;
+	dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr;
+	opb_compression_factor_ycbcr = compression_factor.opb_cf_ycbcr;
+
+	dpb_ubwc_tile_width_pixels = ubwc_tile_w;
+
+	dpb_ubwc_tile_height_pixels = ubwc_tile_h;
+
+	decoder_frame_complexity_factor =
+		(codec_input.complexity_setting == 0) ?
+		400 : ((codec_input.complexity_setting == 1) ? 266 : 100);
+
+	reconstructed_write_bw_factor_rd = (codec_input.complexity_setting == 0) ?
+		105 : 100;
+
+	reference_y_read_bw_factor = llc_saving;
+
+	reference_cbcr_read_bw_factor = llc_saving;
+
+	if (codec_input.codec == CODEC_HEVC) {
+		if (codec_input.lcu_size == 32)
+			bse_tlb_byte_per_lcu = 64;
+		else if (codec_input.lcu_size == 16)
+			bse_tlb_byte_per_lcu = 32;
+		else
+			bse_tlb_byte_per_lcu = 128;
+	} else if ((codec_input.codec == CODEC_H264) ||
+		(codec_input.codec == CODEC_H264_CAVLC)) {
+		bse_tlb_byte_per_lcu = 64;
+	} else if (codec_input.codec == CODEC_VP9) {
+		bse_tlb_byte_per_lcu = 304;
+	}
+
+	codec_output->noc_bw_rd = 0;
+	codec_output->noc_bw_wr = 0;
+	codec_output->ddr_bw_rd = 0;
+	codec_output->ddr_bw_wr = 0;
+
+	large_bw_calculation_fp = 0;
+	large_bw_calculation_fp = ((target_bitrate *
+		decoder_vsp_read_factor + 7) / 8);
+
+	codec_output->vsp_read_noc = large_bw_calculation_fp;
+
+	codec_output->vsp_read_ddr = codec_output->vsp_read_noc;
+
+	large_bw_calculation_fp = ((target_bitrate *
+		bins_to_bits_factor + 7) / 8);
+
+	codec_output->vsp_write_noc = large_bw_calculation_fp;
+	codec_output->vsp_write_ddr = codec_output->vsp_write_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->vsp_read_noc;
+	codec_output->ddr_bw_rd += codec_output->vsp_read_ddr;
+	codec_output->noc_bw_wr += codec_output->vsp_write_noc;
+	codec_output->ddr_bw_wr += codec_output->vsp_write_ddr;
+
+	large_bw_calculation_fp = 0;
+	large_bw_calculation_fp = ((collocated_bytes_per_lcu *
+		lcu_per_frame * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+	codec_output->collocated_rd_noc = large_bw_calculation_fp;
+	codec_output->collocated_wr_noc = codec_output->collocated_rd_noc;
+	codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc;
+	codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc;
+
+	codec_output->collocated_rd_wr_total_noc =
+		(u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc);
+
+	codec_output->collocated_rd_wr_total_ddr =
+		codec_output->collocated_rd_wr_total_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->collocated_rd_noc;
+	codec_output->noc_bw_wr += codec_output->collocated_wr_noc;
+	codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr;
+	codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr;
+
+	large_bw_calculation_fp = 0;
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp :
+		frame420_y_bw_no_ubwc_tile_10bpp) * decoder_frame_complexity_factor;
+
+	large_bw_calculation_fp =
+		(large_bw_calculation_fp + dpb_compression_factor_y - 1) /
+		dpb_compression_factor_y;
+
+	codec_output->dpb_rd_y_noc = large_bw_calculation_fp;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) *
+		decoder_frame_complexity_factor;
+
+	large_bw_calculation_fp =
+		(large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) /
+		dpb_compression_factor_cbcr / 2;
+
+	codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp;
+	codec_output->dpb_rdwr_duetooverlap_noc = 0;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) *
+		reconstructed_write_bw_factor_rd;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) *
+		reconstructed_write_bw_factor_rd;
+
+	large_bw_calculation_fp = large_bw_calculation_fp *
+		(dpb_compression_factor_y / 2 + dpb_compression_factor_cbcr);
+
+	large_bw_calculation_fp = (large_bw_calculation_fp + dpb_compression_factor_y - 1) /
+		dpb_compression_factor_y;
+
+	large_bw_calculation_fp =
+		(large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) /
+		dpb_compression_factor_cbcr;
+
+	codec_output->dpb_wr_noc = large_bw_calculation_fp;
+
+	codec_output->dpb_rd_y_ddr = (llc_enabled_ref_y_rd) ?
+		((codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) /
+		reference_y_read_bw_factor) : codec_output->dpb_rd_y_noc;
+
+	codec_output->dpb_rd_crcb_ddr = (llc_enable_ref_crcb_rd) ?
+		((codec_output->dpb_rd_crcb_noc * 100 +
+		reference_cbcr_read_bw_factor - 1) /
+		reference_cbcr_read_bw_factor) : codec_output->dpb_rd_crcb_noc;
+
+	codec_output->dpb_rdwr_duetooverlap_ddr = 0;
+	codec_output->dpb_wr_ddr = codec_output->dpb_wr_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc;
+	codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc;
+	codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc;
+	codec_output->noc_bw_wr += codec_output->dpb_wr_noc;
+	codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr;
+	codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr;
+	codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr;
+	codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr;
+
+	if (codec_input.linear_opb || codec_input.split_opb) {
+		if (codec_input.linear_opb) {
+			if (codec_input.bitdepth == CODEC_BITDEPTH_8) {
+				large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) *
+				3 / 2 / dpb_to_opb_ratios_ds);
+
+				codec_output->opb_write_total_noc = large_bw_calculation_fp;
+			} else {
+				large_bw_calculation_fp = ((frame420_y_bw_linear_10bpp) *
+				3 / 2 / dpb_to_opb_ratios_ds);
+
+				codec_output->opb_write_total_noc = large_bw_calculation_fp;
+			}
+		} else { /* (CODEC_INPUT.split_opb) */
+			if (codec_input.bitdepth == CODEC_BITDEPTH_8) {
+				large_bw_calculation_fp =
+					(frame420_y_bw_linear_8bpp * 3 / 2 / dpb_to_opb_ratios_ds *
+					100 + opb_compression_factor_ycbcr - 1) /
+					opb_compression_factor_ycbcr;
+
+				codec_output->opb_write_total_noc = large_bw_calculation_fp;
+			} else {
+				large_bw_calculation_fp =
+					(frame420_y_bw_no_ubwc_tile_10bpp * 3 / 2 /
+					dpb_to_opb_ratios_ds * 100 +
+					opb_compression_factor_ycbcr - 1) /
+					opb_compression_factor_ycbcr;
+
+				codec_output->opb_write_total_noc = large_bw_calculation_fp;
+			}
+		}
+	} else {
+		codec_output->opb_write_total_noc = 0;
+	}
+
+	codec_output->opb_write_total_ddr = codec_output->opb_write_total_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_wr += codec_output->opb_write_total_noc;
+	codec_output->ddr_bw_wr += codec_output->opb_write_total_ddr;
+
+	large_bw_calculation_fp = ((bse_tlb_byte_per_lcu * lcu_per_frame *
+		codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+
+	codec_output->bse_tlb_rd_noc = large_bw_calculation_fp;
+
+	if (llc_enabled_bse_tlb)
+		codec_output->bse_tlb_rd_ddr = 0;
+	else
+		codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc;
+
+	codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc;
+
+	if (llc_enabled_bse_tlb)
+		codec_output->bse_tlb_wr_ddr = 0;
+	else
+		codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc;
+	codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr;
+	codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc;
+	codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr;
+
+	codec_output->mmu_rd_ddr = 0;
+	codec_output->mmu_rd_noc = 0;
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->mmu_rd_noc;
+	codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr;
+
+	return 0;
+}
+
+static int calculate_bandwidth_encoder_iris3(struct api_calculation_input codec_input,
+					     struct api_calculation_bw_output *codec_output)
+{
+	/* common control parameters */
+	u32 frame_width;
+	u32 frame_height;
+	u32 frame_lcu_size;
+	u32 lcu_per_frame;
+	u32 target_bitrate;
+	u32 collocated_bytes_per_lcu;
+
+	u32 frame420_y_bw_linear_8bpp;
+	u32 frame420_y_bw_no_ubwc_tile_10bpp;
+	u32 frame420_y_bw_linear_10bpp;
+
+	u16 ubwc_tile_w;
+	u16 ubwc_tile_h;
+
+	u32 dpb_compression_factor_y;
+	u32 dpb_compression_factor_cbcr;
+
+	u32 reconstructed_write_bw_factor_rd;
+	u32 reference_y_read_bw_factor;
+	u32 reference_crcb_read_bw_factor;
+
+	/* encoder control parameters */
+	u32 en_vertical_tiles_width = 960;
+
+	u8 en_rotation_90_270 = 0;
+	/* TODO Can we use (codec_input.status_llc_onoff) for enc_llc_*? */
+	u8 en_llc_enable_ref_rd_crcb = 0;
+	u8 en_llc_enable_rec_wr_uncompleted = 0;
+	u8 en_llc_enable_ref_rd_y_overlap = 0;
+
+	u32 en_bins_to_bits_factor = 4;
+	u32 en_search_windows_size_horizontal = 96;
+
+	u32 en_tile_number;
+	u32 ipb_compression_factor_y;
+	u32 ipb_compression_factor;
+
+	u32 large_bw_calculation_fp = 0;
+
+	/* TODO Are these really needed in Encoder? */
+	u32 bse_tlb_byte_per_lcu = 0;
+	u8 llc_enabled_bse_tlb = 1;
+
+	/*H265D BSE tlb in LLC will be pored in Kailua */
+	llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0;
+
+	frame_width = codec_input.frame_width;
+	frame_height = codec_input.frame_height;
+	if (codec_input.codec == CODEC_H264 ||
+	    codec_input.codec == CODEC_H264_CAVLC) {
+		frame_lcu_size = 16;
+		collocated_bytes_per_lcu = 16;
+	} else if (codec_input.codec == CODEC_HEVC) {
+		frame_lcu_size = 32;
+		collocated_bytes_per_lcu = 64;
+	} else {
+		/* TODO What is the value for VP9 ? */
+		frame_lcu_size = 16;
+		collocated_bytes_per_lcu = 16; /* TODO Fixes Uninitialized compilation error. */
+	}
+
+	lcu_per_frame =
+		calculate_number_lcus_iris3(frame_width, frame_height, frame_lcu_size);
+
+	bse_tlb_byte_per_lcu = 16; /* TODO Should be in common declaration */
+
+	target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */
+
+	ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48;
+	ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4;
+
+	/* yuv */
+	if (codec_input.ipb_yuvrgb == 0) {
+		frame420_y_bw_linear_8bpp =
+			((calculate_number_ubwctiles_iris3(frame_width, frame_height,
+			32, 8) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+	} else { /* RGBA */
+		frame420_y_bw_linear_8bpp =
+			((calculate_number_ubwctiles_iris3(frame_width, frame_height,
+			6, 4) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+	}
+
+	frame420_y_bw_no_ubwc_tile_10bpp =
+		((calculate_number_ubwctiles_iris3(frame_width, frame_height, 48, 4) *
+		256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+
+	frame420_y_bw_linear_10bpp = ((frame_width * frame_height *
+		codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000;
+
+	/* TODO Integrate Compression Ratio returned by FW */
+	get_compression_factors(&compression_factor, codec_input);
+	dpb_compression_factor_y = compression_factor.dpb_cf_y;
+	dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr;
+	ipb_compression_factor_y = compression_factor.ipb_cr_y;
+	ipb_compression_factor = compression_factor.ipb_cr;
+
+	en_tile_number = (frame_width % en_vertical_tiles_width) ?
+		((frame_width / en_vertical_tiles_width) + 1) :
+		(frame_width / en_vertical_tiles_width);
+
+	en_tile_number = en_tile_number * 100;
+
+	/* ceil is same as excel roundup (float, 0); */
+	reconstructed_write_bw_factor_rd = ((en_tile_number - 100) * 2 *
+		((codec_input.lcu_size + ubwc_tile_w - 1) / ubwc_tile_w) *
+		ubwc_tile_w + (frame_width - 1)) / (frame_width) + 100;
+
+	reference_y_read_bw_factor = ((en_tile_number - 100) * 2 *
+		((en_search_windows_size_horizontal + ubwc_tile_w - 1) / ubwc_tile_w) *
+		ubwc_tile_w + (frame_width - 1)) / frame_width + 100;
+
+	reference_crcb_read_bw_factor = 150;
+
+	codec_output->noc_bw_rd = 0;
+	codec_output->noc_bw_wr = 0;
+	codec_output->ddr_bw_rd = 0;
+	codec_output->ddr_bw_wr = 0;
+
+	large_bw_calculation_fp = (target_bitrate * en_bins_to_bits_factor + 7) / 8;
+	codec_output->vsp_read_noc = large_bw_calculation_fp;
+	codec_output->vsp_read_ddr = codec_output->vsp_read_noc;
+	large_bw_calculation_fp = (target_bitrate + 7) / 8;
+
+	codec_output->vsp_write_noc = codec_output->vsp_read_noc +
+		large_bw_calculation_fp;
+
+	codec_output->vsp_write_ddr = codec_output->vsp_write_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->vsp_read_noc;
+	codec_output->ddr_bw_rd += codec_output->vsp_read_ddr;
+	codec_output->noc_bw_wr += codec_output->vsp_write_noc;
+	codec_output->ddr_bw_wr += codec_output->vsp_write_ddr;
+
+	large_bw_calculation_fp = ((collocated_bytes_per_lcu * lcu_per_frame *
+		codec_input.frame_rate + 999) / 1000 + 999) / 1000;
+
+	codec_output->collocated_rd_noc = large_bw_calculation_fp;
+	codec_output->collocated_wr_noc = codec_output->collocated_rd_noc;
+	codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc;
+	codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc;
+
+	codec_output->collocated_rd_wr_total_noc =
+		(u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc);
+	codec_output->collocated_rd_wr_total_ddr =
+		codec_output->collocated_rd_wr_total_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->collocated_rd_noc;
+	codec_output->noc_bw_wr += codec_output->collocated_wr_noc;
+	codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr;
+	codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr;
+
+	large_bw_calculation_fp = 0;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp :
+		frame420_y_bw_no_ubwc_tile_10bpp) * reference_y_read_bw_factor;
+
+	large_bw_calculation_fp = (large_bw_calculation_fp *
+		iris3_en_readfactor[codec_input.hierachical_layer]);
+
+	large_bw_calculation_fp = (large_bw_calculation_fp +
+		dpb_compression_factor_y - 1) / dpb_compression_factor_y;
+
+	large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000;
+
+	codec_output->dpb_rd_y_noc = large_bw_calculation_fp;
+
+	large_bw_calculation_fp = 0;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp :
+		frame420_y_bw_no_ubwc_tile_10bpp) * reference_crcb_read_bw_factor / 2;
+
+	large_bw_calculation_fp = large_bw_calculation_fp *
+		iris3_en_readfactor[codec_input.hierachical_layer];
+
+	large_bw_calculation_fp = (large_bw_calculation_fp +
+		dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr;
+
+	large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000;
+	codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp;
+
+	large_bw_calculation_fp = 0;
+
+	large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ?
+		frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) *
+		reconstructed_write_bw_factor_rd *
+		iris3_en_writefactor[codec_input.hierachical_layer] /
+		iris3_en_frame_num_parallel;
+
+	large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000;
+
+	large_bw_calculation_fp = large_bw_calculation_fp *
+		(dpb_compression_factor_cbcr + dpb_compression_factor_y / 2);
+
+	large_bw_calculation_fp = (large_bw_calculation_fp +
+		dpb_compression_factor_y - 1) / dpb_compression_factor_y;
+
+	large_bw_calculation_fp = (large_bw_calculation_fp +
+		dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr;
+
+	codec_output->dpb_wr_noc = large_bw_calculation_fp;
+
+	/*
+	 * Summary:
+	 * by default (for both HFR and HSR cases) :
+	 *	-Any resolution and fps >= 120, enable layering.
+	 * (120 -> 3, 240 -> 4, 480 -> 5)
+	 *	- (once we enable layering) : 50 per cent frames are Non - reference
+	 *  frames.recon write is disable by Venus firmware
+	 *	- Customer has ability to enable / disable layering.
+	 *  Hence, recon write savings would not be there if customer
+	 *  explicitly disables layer encoding.
+	 */
+
+	/*HFR Cases use alternating rec write if not PWC*/
+	if (codec_input.frame_rate >= 120 && codec_input.complexity_setting != 0)
+		codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2;
+
+	/* for power cases with [B1] adaptive non-ref b frame */
+	/* power caes IbP non reference b */
+	if (codec_input.hierachical_layer >= 1 &&
+	    codec_input.hierachical_layer <= 3 &&
+	    codec_input.complexity_setting != 0)
+		codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2;
+
+	large_bw_calculation_fp = 0;
+	large_bw_calculation_fp = codec_output->dpb_wr_noc *
+		(reconstructed_write_bw_factor_rd - 100);
+
+	large_bw_calculation_fp = (large_bw_calculation_fp +
+		reconstructed_write_bw_factor_rd - 1) / reconstructed_write_bw_factor_rd;
+
+	codec_output->dpb_rdwr_duetooverlap_noc = large_bw_calculation_fp;
+
+	codec_output->dpb_rd_y_ddr = (en_llc_enable_ref_rd_y_overlap) ?
+		(codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) /
+		reference_y_read_bw_factor : codec_output->dpb_rd_y_noc;
+
+	codec_output->dpb_rd_crcb_ddr = (en_llc_enable_ref_rd_crcb) ?
+		(codec_output->dpb_rd_crcb_noc * 100 + reference_crcb_read_bw_factor - 1) /
+		reference_crcb_read_bw_factor : codec_output->dpb_rd_crcb_noc;
+
+	codec_output->dpb_rdwr_duetooverlap_ddr = (en_llc_enable_rec_wr_uncompleted) ?
+		0 : codec_output->dpb_rdwr_duetooverlap_noc;
+
+	codec_output->dpb_wr_ddr = (en_llc_enable_rec_wr_uncompleted) ?
+		0 : codec_output->dpb_wr_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc;
+	codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc;
+	codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc;
+	codec_output->noc_bw_wr += codec_output->dpb_wr_noc;
+	codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr;
+	codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr;
+	codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr;
+	codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr;
+
+	if (codec_input.bitdepth == CODEC_BITDEPTH_8) {
+		if (codec_input.ipb_yuvrgb == 0) { /* yuv */
+			large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) * 3 / 2);
+			codec_output->ipb_rd_total_noc = large_bw_calculation_fp;
+			if (codec_input.linear_ipb == 0) {
+				codec_output->ipb_rd_total_noc =
+					(large_bw_calculation_fp * 100 + ipb_compression_factor
+					 - 1) / ipb_compression_factor;
+			}
+		} else { /* rgb */
+			large_bw_calculation_fp = frame420_y_bw_linear_8bpp;
+			codec_output->ipb_rd_total_noc = large_bw_calculation_fp;
+			if (codec_input.linear_ipb == 0) {
+				if (codec_input.complexity_setting == 0) /* pwc */
+					codec_output->ipb_rd_total_noc =
+						(large_bw_calculation_fp * 100 +
+						en_original_compression_factor_rgba_pwd_iris3
+						- 1) /
+						en_original_compression_factor_rgba_pwd_iris3;
+				else
+					codec_output->ipb_rd_total_noc =
+					(large_bw_calculation_fp * 100 +
+					en_original_compression_factor_rgba_avg_iris3 - 1) /
+					en_original_compression_factor_rgba_avg_iris3;
+			}
+		}
+	} else {
+		if (codec_input.linear_ipb == 1) {
+			large_bw_calculation_fp = (frame420_y_bw_linear_10bpp) * 3 / 2;
+			codec_output->ipb_rd_total_noc = large_bw_calculation_fp;
+		} else {
+			large_bw_calculation_fp = (frame420_y_bw_no_ubwc_tile_10bpp *
+				300 / 2 + ipb_compression_factor - 1) / ipb_compression_factor;
+			codec_output->ipb_rd_total_noc = large_bw_calculation_fp;
+		}
+	}
+
+	if (en_rotation_90_270) {
+		if (codec_input.codec == CODEC_HEVC) {
+			if (codec_input.bitdepth == CODEC_BITDEPTH_8 &&
+			    codec_input.ipb_yuvrgb == 0)
+				codec_output->ipb_rd_total_noc =
+					codec_output->ipb_rd_total_noc * 1;
+			else
+				codec_output->ipb_rd_total_noc =
+					codec_output->ipb_rd_total_noc * 3;
+		} else {
+			codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc * 2;
+		}
+	}
+
+	codec_output->ipb_rd_total_ddr = codec_output->ipb_rd_total_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->ipb_rd_total_noc;
+	codec_output->ddr_bw_rd += codec_output->ipb_rd_total_ddr;
+
+	codec_output->bse_tlb_rd_noc =
+		((bse_tlb_byte_per_lcu * lcu_per_frame * codec_input.frame_rate + 999)
+		/ 1000 + 999) / 1000;
+
+	if (llc_enabled_bse_tlb) /* TODO should be common declaration */
+		codec_output->bse_tlb_rd_ddr = 0;
+	else
+		codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc;
+
+	codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc;
+
+	if (llc_enabled_bse_tlb)
+		codec_output->bse_tlb_wr_ddr = 0;
+	else
+		codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc;
+
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc;
+	codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr;
+	codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc;
+	codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr;
+
+	codec_output->mmu_rd_ddr = 0;
+	codec_output->mmu_rd_noc = 0;
+	/* accumulation */
+	codec_output->noc_bw_rd += codec_output->mmu_rd_noc;
+	codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr;
+
+	return 0;
+}
+
+int msm_vidc_calculate_bandwidth(struct api_calculation_input codec_input,
+				 struct api_calculation_bw_output *codec_output)
+{
+	int rc = 0;
+
+	if (codec_input.decoder_or_encoder == CODEC_DECODER) {
+		rc = calculate_bandwidth_decoder_iris3(codec_input, codec_output);
+	} else if (codec_input.decoder_or_encoder == CODEC_ENCODER) {
+		rc = calculate_bandwidth_encoder_iris3(codec_input, codec_output);
+	} else {
+		d_vpr_e("%s: invalid codec %u\n", __func__, codec_input.decoder_or_encoder);
+		return -EINVAL;
+	}
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (30 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 18:13   ` Konrad Dybcio
  2023-07-28 13:23 ` [PATCH 33/33] iris: enable building of iris video driver Vikash Garodia
                   ` (3 subsequent siblings)
  35 siblings, 1 reply; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements the logic to computer the required clock frequency
by encoder or decoder for a specific usecase. It considers the input
as various parameters configured by client for that usecase.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  | 627 +++++++++++++++++++++
 1 file changed, 627 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c

diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
new file mode 100644
index 0000000..6665aef
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
@@ -0,0 +1,627 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "msm_vidc_debug.h"
+
+#define ENABLE_FINEBITRATE_SUBUHD60 0
+#include "perf_static_model.h"
+
+/*
+ * Chipset Generation Technology: SW/FW overhead profiling
+ * need update with new numbers
+ */
+static u32 frequency_table_iris3[2][6] = {
+	/* //make lowsvs_D1 as invalid; */
+	{533, 444, 366, 338, 240, 0},
+	{800, 666, 549, 507, 360, 0},
+};
+
+ /* Tensilica cycles */
+#define DECODER_VPP_FW_OVERHEAD_IRIS3                                                  66234
+
+/* Tensilica cycles; this is measured in Lahaina 1stage with FW profiling */
+#define DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3                                         93000
+
+#define DECODER_VSP_FW_OVERHEAD_IRIS3 \
+	(DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 - DECODER_VPP_FW_OVERHEAD_IRIS3)
+
+/* Tensilica cycles; encoder has ARP register */
+#define ENCODER_VPP_FW_OVERHEAD_IRIS3                                                  48405
+
+#define ENCODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 \
+	(ENCODER_VPP_FW_OVERHEAD_IRIS3 + DECODER_VSP_FW_OVERHEAD_IRIS3)
+
+#define DECODER_SW_OVERHEAD_IRIS3                                                      489583
+#define ENCODER_SW_OVERHEAD_IRIS3                                                      489583
+
+/* Video IP Core Technology: pipefloor and pipe penlaty */
+static u32 decoder_vpp_target_clk_per_mb_iris3 = 200;
+
+/*
+ * These pipe penalty numbers only applies to 4 pipe
+ * For 2pipe and 1pipe, these numbers need recalibrate
+ */
+static u32 pipe_penalty_iris3[3][3] = {
+	/* NON AV1 */
+	{1059, 1059, 1059},
+	/* AV1 RECOMMENDED TILE 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 */
+	{1410, 1248, 1226},
+	/* AV1 YOUTUBE/NETFLIX TILE 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, 8KUHD_V8X8_V8X1 */
+	{2039, 2464, 1191},
+};
+
+/*
+ * Video IP Core Technology: bitrate constraint
+ * HW limit bitrate table (these values are measured end to end,
+ * fw/sw impacts are also considered)
+ * TODO Can we convert to Cycles/MB? This will remove DIVISION.
+ */
+static u32 bitrate_table_iris3_2stage_fp[4][10] = {
+	/* h264 cavlc */
+	{0, 220, 220, 220, 220, 220, 220, 220, 220, 220},
+	/* h264 cabac */
+	{0, 140, 150, 160, 175, 190, 190, 190, 190, 190},
+	/* h265 */
+	{90, 140, 160, 180, 190, 200, 200, 200, 200, 200},
+	/* vp9 */
+	{90, 90, 90, 90, 90, 90, 90, 90, 90, 90},
+};
+
+/* HW limit bitrate table (these values are measured end to end fw/sw impacts
+ * are also considered
+ */
+static u32 bitrate_table_iris3_1stage_fp[4][10] = { /* 1-stage assume IPPP */
+	/* h264 cavlc */
+	{0, 220, 220, 220, 220, 220, 220, 220, 220, 220},
+	/* h264 cabac */
+	{0, 110, 150, 150, 150, 150, 150, 150, 150, 150},
+	/* h265 */
+	{0, 140, 150, 150, 150, 150, 150, 150, 150, 150},
+	/* vp9 */
+	{0, 70, 70, 70, 70, 70, 70, 70, 70, 70},
+};
+
+static u32 input_bitrate_fp;
+
+/* 8KUHD60; UHD240; 1080p960  with B */
+static u32 fp_pixel_count_bar0 = 3840 * 2160 * 240;
+/* 8KUHD60; UHD240; 1080p960  without B */
+static u32 fp_pixel_count_bar1 = 3840 * 2160 * 240;
+/* 1080p720 */
+static u32 fp_pixel_count_bar2 = 3840 * 2160 * 180;
+/* UHD120 */
+static u32 fp_pixel_count_bar3 = 3840 * 2160 * 120;
+/* UHD90 */
+static u32 fp_pixel_count_bar4 = 3840 * 2160 * 90;
+/* UHD60 */
+static u32 fp_pixel_count_bar5 = 3840 * 2160 * 60;
+/* UHD30; FHD120; HD240 */
+static u32 fp_pixel_count_bar6 = 3840 * 2160 * 30;
+/* FHD60 */
+static u32 fp_pixel_count_bar7 = 1920 * 1080 * 60;
+/* FHD30 */
+static u32 fp_pixel_count_bar8 = 1920 * 1080 * 30;
+
+static u32 codec_encoder_gop_complexity_table_fp[8][3];
+static u32 codec_mbspersession_iris3;
+
+static u32 calculate_number_mbs_iris3(u32 width, u32 height, u32 lcu_size)
+{
+	u32 mbs_width = (width % lcu_size) ?
+		(width / lcu_size + 1) : (width / lcu_size);
+
+	u32 mbs_height = (height % lcu_size) ?
+		(height / lcu_size + 1) : (height / lcu_size);
+
+	return mbs_width * mbs_height * (lcu_size / 16) * (lcu_size / 16);
+}
+
+static int initialize_encoder_complexity_table(void)
+{
+	/* Beging Calculate Encoder GOP Complexity Table and HW Floor numbers */
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 70000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] +
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] /
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY]);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 30000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] +
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] /
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY]);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] = 10000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] = 10000;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] * 100);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] +
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] - 1);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] /
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY]);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] = 0;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] = 1;
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] * 100);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] +
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] - 1);
+
+	codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] =
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] /
+		(codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] +
+		codec_encoder_gop_complexity_table_fp
+		[CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY]);
+
+	return 0;
+}
+
+u32 get_bitrate_entry(u32 pixle_count)
+{
+	u32 bitrate_entry = 0;
+
+	if (pixle_count >= fp_pixel_count_bar1)
+		bitrate_entry = 1;
+	else if (pixle_count >= fp_pixel_count_bar2)
+		bitrate_entry = 2;
+	else if (pixle_count >= fp_pixel_count_bar3)
+		bitrate_entry = 3;
+	else if (pixle_count >= fp_pixel_count_bar4)
+		bitrate_entry = 4;
+	else if (pixle_count >= fp_pixel_count_bar5)
+		bitrate_entry = 5;
+	else if (pixle_count >= fp_pixel_count_bar6)
+		bitrate_entry = 6;
+	else if (pixle_count >= fp_pixel_count_bar7)
+		bitrate_entry = 7;
+	else if (pixle_count >= fp_pixel_count_bar8)
+		bitrate_entry = 8;
+	else
+		bitrate_entry = 9;
+
+	return bitrate_entry;
+}
+
+static int calculate_vsp_min_freq(struct api_calculation_input codec_input,
+				  struct api_calculation_freq_output *codec_output)
+{
+	/*
+	 * VSP calculation
+	 * different methodology from Lahaina
+	 */
+	u32 vsp_hw_min_frequency = 0;
+	/* UInt32 decoder_vsp_fw_overhead = 100 + 5; // amplified by 100x */
+	u32 fw_sw_vsp_offset = 1000 + 55;      /* amplified by 1000x */
+
+	/*
+	 * Ignore fw_sw_vsp_offset, as this is baked into the reference bitrate tables.
+	 *  As a consequence remove x1000 multiplier as well.
+	 */
+	u32 codec = codec_input.codec;
+	/* UInt32 *bitratetable; */
+	u32 pixle_count = codec_input.frame_width *
+		codec_input.frame_height * codec_input.frame_rate;
+
+	u8 bitrate_entry = get_bitrate_entry(pixle_count); /* TODO EXTRACT */
+
+	input_bitrate_fp = ((u32)(codec_input.bitrate_mbps * 100 + 99)) / 100;
+	vsp_hw_min_frequency = frequency_table_iris3[0][1] * input_bitrate_fp * 1000;
+
+	/* 8KUHD60fps with B frame */
+	if (pixle_count >= fp_pixel_count_bar0 &&
+	    codec_input.hierachical_layer != CODEC_GOP_IPP) {
+		/*
+		 *  FORMULA: VSPfreq = NOMINAL * (InputBitrate / ReferenceBitrate);
+		 *  ReferenceBitrate = 0 for,
+		 *     - 1Stage TURBO, all Codecs.
+		 *     - 2Stage TURBO, H264 & H265.
+		 *
+		 *  8KUHD60fps with B frame
+		 *     - bitrate_entry = 0
+		 *     - Clock=NOMINAL for H264 & 2Stage H265.
+		 *       Because bitrate table entry for TURBO is 0.
+		 *
+		 *  TODO : Reduce these conditions by removing the zero entries from Bitrate table.
+		 */
+		vsp_hw_min_frequency = frequency_table_iris3[0][1] *
+			input_bitrate_fp * 1000;
+
+		if (codec_input.codec == CODEC_H264 ||
+		    codec_input.codec == CODEC_H264_CAVLC ||
+		    (codec_input.codec == CODEC_HEVC &&
+		     codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_1S)) {
+			vsp_hw_min_frequency =
+				DIV_ROUND_UP(frequency_table_iris3[0][1], fw_sw_vsp_offset);
+		} else if ((codec_input.codec == CODEC_HEVC &&
+			   codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) ||
+			   codec_input.codec == CODEC_VP9) {
+			if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) {
+				vsp_hw_min_frequency =
+					DIV_ROUND_UP(vsp_hw_min_frequency,
+						     (bitrate_table_iris3_2stage_fp[codec][0] *
+						      fw_sw_vsp_offset));
+			} else {
+				vsp_hw_min_frequency =
+					DIV_ROUND_UP(vsp_hw_min_frequency,
+						     (bitrate_table_iris3_1stage_fp[codec][0] *
+						      fw_sw_vsp_offset));
+			}
+		}
+	} else {
+		vsp_hw_min_frequency = frequency_table_iris3[0][1] *
+			input_bitrate_fp * 1000;
+
+		if (codec_input.codec == CODEC_H264_CAVLC &&
+		    codec_input.entropy_coding_mode == CODEC_ENTROPY_CODING_CAVLC)
+			codec = CODEC_H264_CAVLC;
+		else if (codec_input.codec == CODEC_H264 &&
+			 codec_input.entropy_coding_mode == CODEC_ENTROPY_CODING_CABAC)
+			codec = CODEC_H264;
+
+		if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S)
+			vsp_hw_min_frequency =
+				DIV_ROUND_UP(vsp_hw_min_frequency,
+					     (bitrate_table_iris3_2stage_fp[codec][bitrate_entry]) *
+					      fw_sw_vsp_offset);
+		else
+			vsp_hw_min_frequency =
+				DIV_ROUND_UP(vsp_hw_min_frequency,
+					     (bitrate_table_iris3_1stage_fp[codec][bitrate_entry]) *
+					      fw_sw_vsp_offset);
+	}
+
+	codec_output->vsp_min_freq = vsp_hw_min_frequency;
+	return 0;
+}
+
+static u32 calculate_pipe_penalty(struct api_calculation_input codec_input)
+{
+	u32 pipe_penalty_codec = 0;
+
+	/* decoder */
+	if (codec_input.decoder_or_encoder == CODEC_DECODER)
+		pipe_penalty_codec = pipe_penalty_iris3[0][0];
+	else
+		pipe_penalty_codec = 101;
+
+	return pipe_penalty_codec;
+}
+
+static int calculate_vpp_min_freq(struct api_calculation_input codec_input,
+				  struct api_calculation_freq_output *codec_output)
+{
+	u32 vpp_hw_min_frequency = 0;
+	u32 fmin = 0;
+	u32 tensilica_min_frequency = 0;
+	u32 decoder_vsp_fw_overhead = 100 + 5; /* amplified by 100x */
+	/* UInt32 fw_sw_vsp_offset = 1000 + 55;       amplified by 1000x */
+	/* TODO from calculate_sw_vsp_min_freq */
+	u32 vsp_hw_min_frequency = codec_output->vsp_min_freq;
+	u32 pipe_penalty_codec = 0;
+	u32 fmin_fwoverhead105 = 0;
+	u32 fmin_measured_fwoverhead = 0;
+	u32 lpmode_uhd_cycle_permb = 0;
+	u32 hqmode1080p_cycle_permb = 0;
+	u32 encoder_vpp_target_clk_per_mb = 0;
+
+	codec_mbspersession_iris3 =
+		calculate_number_mbs_iris3(codec_input.frame_width,
+					   codec_input.frame_height,
+					   codec_input.lcu_size) *
+		codec_input.frame_rate;
+
+	/* Section 2. 0  VPP/VSP calculation */
+	if (codec_input.decoder_or_encoder == CODEC_DECODER) { /* decoder */
+		vpp_hw_min_frequency = ((decoder_vpp_target_clk_per_mb_iris3) *
+			(codec_mbspersession_iris3) + codec_input.pipe_num - 1) /
+			(codec_input.pipe_num);
+
+		vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000;
+
+		if (codec_input.pipe_num > 1) {
+			pipe_penalty_codec = calculate_pipe_penalty(codec_input);
+			vpp_hw_min_frequency = (vpp_hw_min_frequency *
+				pipe_penalty_codec + 999) / 1000;
+		}
+
+		if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) {
+			/* FW overhead, convert FW cycles to impact to one pipe */
+			u64 decoder_vpp_fw_overhead = 0;
+
+			decoder_vpp_fw_overhead =
+				DIV_ROUND_UP((DECODER_VPP_FW_OVERHEAD_IRIS3 * 10 *
+				codec_input.frame_rate), 15);
+
+			decoder_vpp_fw_overhead =
+				DIV_ROUND_UP((decoder_vpp_fw_overhead * 1000),
+					     (codec_mbspersession_iris3 *
+					      decoder_vpp_target_clk_per_mb_iris3 /
+					      codec_input.pipe_num));
+
+			decoder_vpp_fw_overhead += 1000;
+			decoder_vpp_fw_overhead = (decoder_vpp_fw_overhead < 1050) ?
+				1050 : decoder_vpp_fw_overhead;
+
+			/* VPP HW + FW */
+			if (codec_input.linear_opb == 1 &&
+			    codec_input.bitdepth == CODEC_BITDEPTH_10)
+				/* multiply by 1.20 for 10b case */
+				decoder_vpp_fw_overhead = 1200 + decoder_vpp_fw_overhead - 1000;
+
+			vpp_hw_min_frequency = (vpp_hw_min_frequency *
+				decoder_vpp_fw_overhead + 999) / 1000;
+
+			/* VSP HW+FW */
+			vsp_hw_min_frequency =
+				(vsp_hw_min_frequency * decoder_vsp_fw_overhead + 99) / 100;
+
+			fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ?
+				vpp_hw_min_frequency : vsp_hw_min_frequency;
+		} else {
+			/* 1-stage need SW cycles + FW cycles + HW time */
+			if (codec_input.linear_opb == 1 &&
+			    codec_input.bitdepth == CODEC_BITDEPTH_10)
+				/* multiply by 1.20 for 10b linear case */
+				vpp_hw_min_frequency =
+					(vpp_hw_min_frequency * 1200 + 999) / 1000;
+
+			/*
+			 * HW time
+			 * comment: 02/23/2021 SY: the bitrate is measured bitrate,
+			 * the overlapping effect is already considered into bitrate.
+			 * no need to add extra anymore
+			 */
+			fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ?
+				vpp_hw_min_frequency : vsp_hw_min_frequency;
+
+			/* FW time */
+			fmin_fwoverhead105 = (fmin * 105 + 99) / 100;
+			fmin_measured_fwoverhead = fmin +
+				(((DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 *
+				codec_input.frame_rate * 10 + 14) / 15 + 999) / 1000 + 999) /
+				1000;
+
+			fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ?
+				fmin_fwoverhead105 : fmin_measured_fwoverhead;
+		}
+
+		tensilica_min_frequency = (DECODER_SW_OVERHEAD_IRIS3 * 10 + 14) / 15;
+		tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000;
+		tensilica_min_frequency = tensilica_min_frequency * codec_input.frame_rate;
+		tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000;
+		fmin = (tensilica_min_frequency > fmin) ? tensilica_min_frequency : fmin;
+	} else { /* encoder */
+		/* Decide LP/HQ */
+		u8 hq_mode = 0;
+
+		if (codec_input.pipe_num > 1)
+			if (codec_input.frame_width * codec_input.frame_height <=
+				1920 * 1080)
+				if (codec_input.frame_width * codec_input.frame_height *
+					codec_input.frame_rate <= 1920 * 1080 * 60)
+					hq_mode = 1;
+
+		codec_output->enc_hqmode = hq_mode;
+
+		/* Section 1. 0 */
+		/* TODO ONETIME call, should be in another place. */
+		initialize_encoder_complexity_table();
+
+		/* End Calculate Encoder GOP Complexity Table */
+
+		/* VPP base cycle */
+		lpmode_uhd_cycle_permb = (320 *
+			codec_encoder_gop_complexity_table_fp
+			[codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY]
+			+ 99) / 100;
+
+		if (codec_input.frame_width == 1920 &&
+		    (codec_input.frame_height == 1080 ||
+		     codec_input.frame_height == 1088) &&
+		    codec_input.frame_rate >= 480)
+			lpmode_uhd_cycle_permb = (90 * 4 *
+				codec_encoder_gop_complexity_table_fp
+				[codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY]
+				+ 99) / 100;
+
+		if (codec_input.frame_width == 1280 &&
+		    (codec_input.frame_height == 720 ||
+		     codec_input.frame_height == 768) &&
+		    codec_input.frame_rate >= 960)
+			lpmode_uhd_cycle_permb = (99 * 4 *
+				codec_encoder_gop_complexity_table_fp
+				[codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY]
+				+ 99) / 100;
+
+		hqmode1080p_cycle_permb = (675 *
+			codec_encoder_gop_complexity_table_fp
+			[codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY]
+			+ 99) / 100;
+
+		encoder_vpp_target_clk_per_mb = (hq_mode) ?
+			hqmode1080p_cycle_permb : lpmode_uhd_cycle_permb;
+
+		vpp_hw_min_frequency = ((encoder_vpp_target_clk_per_mb) *
+			(codec_mbspersession_iris3) + codec_input.pipe_num - 1) /
+			(codec_input.pipe_num);
+
+		vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000;
+
+		if (codec_input.pipe_num > 1) {
+			u32 pipe_penalty_codec = 101;
+
+			vpp_hw_min_frequency = (vpp_hw_min_frequency *
+				pipe_penalty_codec + 99) / 100;
+		}
+
+		if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) {
+			/* FW overhead, convert FW cycles to impact to one pipe */
+			u64 encoder_vpp_fw_overhead = 0;
+
+			encoder_vpp_fw_overhead =
+				DIV_ROUND_UP((ENCODER_VPP_FW_OVERHEAD_IRIS3 * 10 *
+				codec_input.frame_rate), 15);
+
+			encoder_vpp_fw_overhead =
+				DIV_ROUND_UP((encoder_vpp_fw_overhead * 1000),
+					     (codec_mbspersession_iris3 *
+					      encoder_vpp_target_clk_per_mb /
+					      codec_input.pipe_num));
+
+			encoder_vpp_fw_overhead += 1000;
+
+			encoder_vpp_fw_overhead = (encoder_vpp_fw_overhead < 1050) ?
+				1050 : encoder_vpp_fw_overhead;
+
+			/* VPP HW + FW */
+			vpp_hw_min_frequency = (vpp_hw_min_frequency *
+				encoder_vpp_fw_overhead + 999) / 1000;
+
+			/* TODO : decoder_vsp_fw_overhead? */
+			vsp_hw_min_frequency = (vsp_hw_min_frequency *
+				decoder_vsp_fw_overhead + 99) / 100;
+
+			fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ?
+				vpp_hw_min_frequency : vsp_hw_min_frequency;
+		} else {
+			/* HW time */
+			fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ?
+				vpp_hw_min_frequency : vsp_hw_min_frequency;
+
+			/* FW time */
+			fmin_fwoverhead105 = (fmin * 105 + 99) / 100;
+			fmin_measured_fwoverhead = fmin +
+				(((DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 *
+				codec_input.frame_rate * 10 + 14) / 15 + 999) /
+				1000 + 999) / 1000;
+
+			fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ?
+				fmin_fwoverhead105 : fmin_measured_fwoverhead;
+			/* SW time */
+		}
+
+		tensilica_min_frequency = (ENCODER_SW_OVERHEAD_IRIS3 * 10 + 14) / 15;
+		tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000;
+
+		tensilica_min_frequency = tensilica_min_frequency *
+			codec_input.frame_rate;
+
+		tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000;
+
+		fmin = (tensilica_min_frequency > fmin) ?
+			tensilica_min_frequency : fmin;
+	}
+
+	codec_output->vpp_min_freq = vpp_hw_min_frequency;
+	codec_output->vsp_min_freq = vsp_hw_min_frequency;
+	codec_output->tensilica_min_freq = tensilica_min_frequency;
+	codec_output->hw_min_freq = fmin;
+
+	return 0;
+}
+
+int msm_vidc_calculate_frequency(struct api_calculation_input codec_input,
+				 struct api_calculation_freq_output *codec_output)
+{
+	int rc = 0;
+
+	rc = calculate_vsp_min_freq(codec_input, codec_output);
+	if (rc)
+		return rc;
+
+	rc = calculate_vpp_min_freq(codec_input, codec_output);
+
+	return rc;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [PATCH 33/33] iris: enable building of iris video driver
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (31 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency Vikash Garodia
@ 2023-07-28 13:23 ` Vikash Garodia
  2023-07-28 14:40   ` Dmitry Baryshkov
  2023-07-28 15:25   ` Bryan O'Donoghue
  2023-07-28 13:32 ` [PATCH 00/33] Qualcomm video decoder/encoder driver Dmitry Baryshkov
                   ` (2 subsequent siblings)
  35 siblings, 2 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-07-28 13:23 UTC (permalink / raw)
  To: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita, Vikash Garodia

From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This adds iris driver Makefile and Kconfig, also changes
v4l2 platform/qcom Makefile/Kconfig in order to
enable compilation of the driver.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 drivers/media/platform/qcom/Kconfig       |  1 +
 drivers/media/platform/qcom/Makefile      |  1 +
 drivers/media/platform/qcom/iris/Kconfig  | 15 ++++++++++
 drivers/media/platform/qcom/iris/Makefile | 46 +++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/Kconfig
 create mode 100644 drivers/media/platform/qcom/iris/Makefile

diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
index cc5799b..b86bebd 100644
--- a/drivers/media/platform/qcom/Kconfig
+++ b/drivers/media/platform/qcom/Kconfig
@@ -4,3 +4,4 @@ comment "Qualcomm media platform drivers"
 
 source "drivers/media/platform/qcom/camss/Kconfig"
 source "drivers/media/platform/qcom/venus/Kconfig"
+source "drivers/media/platform/qcom/iris/Kconfig"
diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
index 4f055c3..83eea29 100644
--- a/drivers/media/platform/qcom/Makefile
+++ b/drivers/media/platform/qcom/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y += camss/
 obj-y += venus/
+obj-y += iris/
diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig
new file mode 100644
index 0000000..d434c31
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_QCOM_IRIS
+	tristate "Qualcomm Iris V4L2 encoder/decoder driver"
+	depends on V4L_MEM2MEM_DRIVERS
+	depends on VIDEO_DEV && QCOM_SMEM
+	depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
+	select QCOM_MDT_LOADER if ARCH_QCOM
+	select QCOM_SCM
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	select DMABUF_HEAPS
+	help
+	  This is a V4L2 driver for Qualcomm Iris video accelerator
+	  hardware. It accelerates encoding and decoding operations
+	  on various Qualcomm SoCs.
+	  To compile this driver as a module choose m here.
diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
new file mode 100644
index 0000000..e681c4f
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/Makefile
@@ -0,0 +1,46 @@
+KBUILD_OPTIONS+= VIDEO_ROOT=$(KERNEL_SRC)/$(M)
+
+VIDEO_COMPILE_TIME = $(shell date)
+VIDEO_COMPILE_BY = $(shell whoami | sed 's/\\/\\\\/')
+VIDEO_COMPILE_HOST = $(shell uname -n)
+VIDEO_GEN_PATH = $(srctree)/$(src)/vidc/inc/video_generated_h
+
+$(shell echo '#define VIDEO_COMPILE_TIME "$(VIDEO_COMPILE_TIME)"' > $(VIDEO_GEN_PATH))
+$(shell echo '#define VIDEO_COMPILE_BY "$(VIDEO_COMPILE_BY)"' >> $(VIDEO_GEN_PATH))
+$(shell echo '#define VIDEO_COMPILE_HOST "$(VIDEO_COMPILE_HOST)"' >> $(VIDEO_GEN_PATH))
+
+iris-objs += vidc/src/msm_vidc_v4l2.o \
+                  vidc/src/msm_vidc_vb2.o \
+                  vidc/src/msm_vidc.o \
+                  vidc/src/msm_vdec.o \
+                  vidc/src/msm_venc.o \
+                  vidc/src/msm_vidc_driver.o \
+                  vidc/src/msm_vidc_control.o \
+                  vidc/src/msm_vidc_buffer.o \
+                  vidc/src/msm_vidc_power.o \
+                  vidc/src/msm_vidc_probe.o \
+                  vidc/src/resources.o \
+                  vidc/src/firmware.o \
+                  vidc/src/msm_vidc_debug.o \
+                  vidc/src/msm_vidc_memory.o \
+                  vidc/src/venus_hfi.o \
+                  vidc/src/venus_hfi_queue.o \
+                  vidc/src/hfi_packet.o \
+                  vidc/src/venus_hfi_response.o \
+                  vidc/src/msm_vidc_state.o \
+                  platform/common/src/msm_vidc_platform.o \
+                  platform/sm8550/src/msm_vidc_sm8550.o \
+                  variant/common/src/msm_vidc_variant.o \
+                  variant/iris3/src/msm_vidc_buffer_iris3.o \
+                  variant/iris3/src/msm_vidc_iris3.o \
+                  variant/iris3/src/msm_vidc_power_iris3.o \
+                  variant/iris3/src/msm_vidc_bus_iris3.o \
+                  variant/iris3/src/msm_vidc_clock_iris3.o
+
+obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o
+
+ccflags-y += -I$(srctree)/$(src)/vidc/inc
+ccflags-y += -I$(srctree)/$(src)/platform/common/inc
+ccflags-y += -I$(srctree)/$(src)/platform/sm8550/inc
+ccflags-y += -I$(srctree)/$(src)/variant/common/inc
+ccflags-y += -I$(srctree)/$(src)/variant/iris3/inc
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (32 preceding siblings ...)
  2023-07-28 13:23 ` [PATCH 33/33] iris: enable building of iris video driver Vikash Garodia
@ 2023-07-28 13:32 ` Dmitry Baryshkov
  2023-07-28 17:38   ` Nicolas Dufresne
  2023-07-28 14:01 ` Dmitry Baryshkov
  2023-07-28 14:34 ` Bryan O'Donoghue
  35 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 13:32 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> This patch series introduces support for Qualcomm new video acceleration
> hardware architecture, used for video stream decoding/encoding. This driver
> is based on new communication protocol between video hardware and application
> processor.
> 
> This driver comes with below capabilities:
> - V4L2 complaint video driver with M2M and STREAMING capability.
> - Supports H264, H265, VP9 decoders.
> - Supports H264, H265 encoders.
> 
> This driver comes with below features:
> - Centralized resource and memory management.
> - Centralized management of core and instance states.
> - Defines platform specific capabilities and features. As a results, it provides
>    a single point of control to enable/disable a given feature depending on
>    specific platform capabilities.
> - Handles hardware interdependent configurations. For a given configuration from
>    client, the driver checks for hardware dependent configuration/s and updates
>    the same.
> - Handles multiple complex video scenarios involving state transitions - DRC,
>    Drain, Seek, back to back DRC, DRC during Drain sequence, DRC during Seek
>    sequence.
> - Introduces a flexible way for driver to subscribe for any property with
>    hardware. Hardware would inform driver with those subscribed property with any
>    change in value.
> - Introduces performance (clock and bus) model based on new hardware
>    architecture.
> - Introduces multi thread safe design to handle communication between client and
>    hardware.
> - Adapts encoder quality improvements available in new hardware architecture.
> - Implements asynchronous communication with hardware to achieve better
>    experience in low latency usecases.
> - Supports multi stage hardware architecture for encode/decode.
> - Output and capture planes are controlled independently. Thereby providing a
>    way to reconfigure individual plane.
> - Hardware packetization layer supports synchronization between configuration
>    packet and data packet.
> - Introduces a flexibility to receive a hardware response for a given command
>    packet.
> - Native hardware support of LAST flag which is mandatory to align with port
>    reconfiguration and DRAIN sequence as per V4L guidelines.
> - Native hardware support for drain sequence.
> 
> I think that the driver is in good shape for mainline kernel, and I hope the
> review comments will help to improve it, so please do review, and make comments.

No bindings, no driver. Please post start the series from the bindings.

> 
> Dikshita Agarwal (17):
>    iris: vidc: add core functions
>    iris: add vidc wrapper file
>    iris: vidc: add vb2 ops
>    iris: vidc: add helpers for memory management
>    iris: vidc: add helper functions for resource management
>    iris: vidc: add helper functions for power management
>    iris: add helpers for media format
>    iris: vidc: add PIL functionality for video firmware
>    iris: platform: add platform files
>    iris: platform: sm8550: add capability file for sm8550
>    iris: variant: add helper functions for register handling
>    iris: variant: iris3: add iris3 specific ops
>    iris: variant: iris3: add helpers for buffer size calculations
>    iris: variant: iris3: add helper for bus and clock calculation
>    iris: variant: iris: implement the logic to compute bus bandwidth
>    iris: variant: iris3: implement logic to compute clock frequency
>    iris: enable building of iris video driver
> 
> Vikash Garodia (16):
>    MAINTAINERS: Add Qualcomm Iris video accelerator driver
>    iris: vidc: add v4l2 wrapper file
>    iris: vidc: define video core and instance context
>    iris: iris: add video encoder files
>    iris: vidc: add video decoder files
>    iris: vidc: add control files
>    iris: vidc: add helper functions
>    iris: vidc: add helpers for state management
>    iris: add vidc buffer files
>    iris: vidc: define various structures and enum
>    iris: vidc: hfi: add Host Firmware Interface (HFI)
>    iris: vidc: hfi: add Host Firmware Interface (HFI) response handling
>    iris: vidc: hfi: add helpers for handling shared queues
>    iris: vidc: hfi: Add packetization layer
>    iris: vidc: hfi: defines HFI properties and enums
>    iris: vidc: add debug files
> 
>   MAINTAINERS                                        |   10 +
>   drivers/media/platform/qcom/Kconfig                |    1 +
>   drivers/media/platform/qcom/Makefile               |    1 +
>   drivers/media/platform/qcom/iris/Kconfig           |   15 +
>   drivers/media/platform/qcom/iris/Makefile          |   46 +
>   .../iris/platform/common/inc/msm_vidc_platform.h   |  305 ++
>   .../iris/platform/common/src/msm_vidc_platform.c   | 2499 ++++++++++++
>   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
>   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++
>   .../iris/variant/common/inc/msm_vidc_variant.h     |   22 +
>   .../iris/variant/common/src/msm_vidc_variant.c     |  163 +
>   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 +++++++
>   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
>   .../qcom/iris/variant/iris3/inc/msm_vidc_iris3.h   |   15 +
>   .../iris/variant/iris3/inc/msm_vidc_power_iris3.h  |   17 +
>   .../iris/variant/iris3/inc/perf_static_model.h     |  229 ++
>   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 +++
>   .../iris/variant/iris3/src/msm_vidc_bus_iris3.c    |  884 ++++
>   .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  |  627 +++
>   .../qcom/iris/variant/iris3/src/msm_vidc_iris3.c   |  954 +++++
>   .../iris/variant/iris3/src/msm_vidc_power_iris3.c  |  345 ++
>   .../media/platform/qcom/iris/vidc/inc/firmware.h   |   18 +
>   .../platform/qcom/iris/vidc/inc/hfi_command.h      |  190 +
>   .../media/platform/qcom/iris/vidc/inc/hfi_packet.h |   52 +
>   .../platform/qcom/iris/vidc/inc/hfi_property.h     |  666 +++
>   .../platform/qcom/iris/vidc/inc/msm_media_info.h   |  599 +++
>   .../media/platform/qcom/iris/vidc/inc/msm_vdec.h   |   40 +
>   .../media/platform/qcom/iris/vidc/inc/msm_venc.h   |   34 +
>   .../media/platform/qcom/iris/vidc/inc/msm_vidc.h   |   60 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_buffer.h  |   32 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_control.h |   26 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_core.h    |  165 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   |  186 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_driver.h  |  352 ++
>   .../platform/qcom/iris/vidc/inc/msm_vidc_inst.h    |  207 +
>   .../qcom/iris/vidc/inc/msm_vidc_internal.h         |  787 ++++
>   .../platform/qcom/iris/vidc/inc/msm_vidc_memory.h  |   83 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_power.h   |   94 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_state.h   |  102 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |   77 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |   39 +
>   .../media/platform/qcom/iris/vidc/inc/resources.h  |  259 ++
>   .../media/platform/qcom/iris/vidc/inc/venus_hfi.h  |   66 +
>   .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |   89 +
>   .../qcom/iris/vidc/inc/venus_hfi_response.h        |   26 +
>   .../media/platform/qcom/iris/vidc/src/firmware.c   |  294 ++
>   .../media/platform/qcom/iris/vidc/src/hfi_packet.c |  657 +++
>   .../media/platform/qcom/iris/vidc/src/msm_vdec.c   | 2091 ++++++++++
>   .../media/platform/qcom/iris/vidc/src/msm_venc.c   | 1484 +++++++
>   .../media/platform/qcom/iris/vidc/src/msm_vidc.c   |  841 ++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_buffer.c  |  290 ++
>   .../platform/qcom/iris/vidc/src/msm_vidc_control.c |  824 ++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   |  581 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_driver.c  | 4276 ++++++++++++++++++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_memory.c  |  448 ++
>   .../platform/qcom/iris/vidc/src/msm_vidc_power.c   |  560 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   |  660 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_state.c   | 1607 ++++++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    |  953 +++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     |  605 +++
>   .../media/platform/qcom/iris/vidc/src/resources.c  | 1321 ++++++
>   .../media/platform/qcom/iris/vidc/src/venus_hfi.c  | 1503 +++++++
>   .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  |  537 +++
>   .../qcom/iris/vidc/src/venus_hfi_response.c        | 1607 ++++++++
>   64 files changed, 35357 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/Kconfig
>   create mode 100644 drivers/media/platform/qcom/iris/Makefile
>   create mode 100644 drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
>   create mode 100644 drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/firmware.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/resources.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/firmware.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/resources.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c
> 

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
@ 2023-07-28 13:34   ` Dmitry Baryshkov
  2023-08-14 18:59     ` Dikshita Agarwal
  2023-07-28 16:23   ` Bjorn Andersson
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 13:34 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> Here is the implementation of v4l2 wrapper functions for all
> v4l2 IOCTLs.

Please do not describe the patch. "Here is..." , "This patch...", "This 
commit..." is a bad style. Please describe _why_ you are doing this. In 
other words, what is the purpose of adding such wrappers. Please rewrite 
your commit messages describing the reasons, not the patch contents.

> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>   2 files changed, 1030 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> new file mode 100644
> index 0000000..3766c9d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_V4L2_H_
> +#define _MSM_VIDC_V4L2_H_
> +
> +#include <linux/fs.h>
> +#include <linux/poll.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-ioctl.h>
> +
> +int msm_v4l2_open(struct file *filp);
> +int msm_v4l2_close(struct file *filp);
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap);
> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
> +		      struct v4l2_fmtdesc *f);
> +int msm_v4l2_try_fmt(struct file *file, void *fh,
> +		     struct v4l2_format *f);
> +int msm_v4l2_s_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_g_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_s_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_g_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_s_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_g_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_reqbufs(struct file *file, void *fh,
> +		     struct v4l2_requestbuffers *b);
> +int msm_v4l2_querybuf(struct file *file, void *fh,
> +		      struct v4l2_buffer *b);
> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
> +			 struct v4l2_create_buffers *b);
> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
> +			 struct v4l2_buffer *b);
> +int msm_v4l2_qbuf(struct file *file, void *fh,
> +		  struct v4l2_buffer *b);
> +int msm_v4l2_dqbuf(struct file *file, void *fh,
> +		   struct v4l2_buffer *b);
> +int msm_v4l2_streamon(struct file *file, void *fh,
> +		      enum v4l2_buf_type i);
> +int msm_v4l2_streamoff(struct file *file, void *fh,
> +		       enum v4l2_buf_type i);
> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
> +			     const struct v4l2_event_subscription *sub);
> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
> +			       const struct v4l2_event_subscription *sub);
> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_decoder_cmd *enc);
> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_decoder_cmd *dec);
> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
> +			     struct v4l2_frmsizeenum *fsize);
> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
> +				 struct v4l2_frmivalenum *fival);
> +int msm_v4l2_queryctrl(struct file *file, void *fh,
> +		       struct v4l2_queryctrl *ctrl);
> +int msm_v4l2_querymenu(struct file *file, void *fh,
> +		       struct v4l2_querymenu *qmenu);
> +unsigned int msm_v4l2_poll(struct file *filp,
> +			   struct poll_table_struct *pt);
> +void msm_v4l2_m2m_device_run(void *priv);
> +void msm_v4l2_m2m_job_abort(void *priv);
> +
> +#endif // _MSM_VIDC_V4L2_H_
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> new file mode 100644
> index 0000000..6dfb18b
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> @@ -0,0 +1,953 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "msm_vidc.h"
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_inst.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_v4l2.h"
> +
> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
> +{
> +	if (!filp || !filp->private_data)
> +		return NULL;
> +	return container_of(filp->private_data,
> +					struct msm_vidc_inst, fh);
> +}
> +
> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
> +{
> +	int poll = 0;
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return POLLERR;
> +	}
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		poll = POLLERR;
> +		goto exit;
> +	}
> +
> +	poll = msm_vidc_poll((void *)inst, filp, pt);
> +	if (poll)
> +		goto exit;
> +
> +exit:
> +	put_inst(inst);
> +	return poll;
> +}
> +
> +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 *inst;
> +
> +	inst = msm_vidc_open(core, vid_dev->type);
> +	if (!inst) {
> +		d_vpr_e("Failed to create instance, type = %d\n",
> +			vid_dev->type);
> +		return -ENOMEM;
> +	}
> +	filp->private_data = &inst->fh;
> +	return 0;
> +}
> +
> +int msm_v4l2_close(struct file *filp)
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +
> +	inst = get_vidc_inst(filp, NULL);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_close(inst);
> +	filp->private_data = NULL;
> +	return rc;
> +}
> +
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !cap) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_querycap((void *)inst, cap);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_fmt(struct file *filp, void *fh,
> +		      struct v4l2_fmtdesc *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_fmt((void *)inst, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_fmt(struct file *filp, void *fh,
> +		   struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_fmt(struct file *filp, void *fh,
> +		   struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_fmt((void *)inst, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_selection(struct file *filp, void *fh,
> +			 struct v4l2_selection *s)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !s) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_s_selection((void *)inst, s);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_selection(struct file *filp, void *fh,
> +			 struct v4l2_selection *s)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !s) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_selection((void *)inst, s);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_parm(struct file *filp, void *fh,
> +		    struct v4l2_streamparm *a)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !a) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_s_param((void *)inst, a);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_parm(struct file *filp, void *fh,
> +		    struct v4l2_streamparm *a)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !a) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_param((void *)inst, a);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_reqbufs(struct file *filp, void *fh,
> +		     struct v4l2_requestbuffers *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_querybuf(struct file *filp, void *fh,
> +		      struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_querybuf((void *)inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
> +			 struct v4l2_create_buffers *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_create_bufs((void *)inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
> +			 struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	struct video_device *vdev = video_devdata(filp);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_qbuf(struct file *filp, void *fh,
> +		  struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	struct video_device *vdev = video_devdata(filp);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
> +	if (rc)
> +		goto exit;
> +
> +exit:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_dqbuf(struct file *filp, void *fh,
> +		   struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_dqbuf(inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_streamon(struct file *filp, void *fh,
> +		      enum v4l2_buf_type i)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto exit;
> +	}
> +
> +	rc = msm_vidc_streamon((void *)inst, i);
> +	if (rc)
> +		goto exit;
> +
> +exit:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_streamoff(struct file *filp, void *fh,
> +		       enum v4l2_buf_type i)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_streamoff((void *)inst, i);
> +	if (rc)
> +		i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
> +
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
> +			     const struct v4l2_event_subscription *sub)
> +{
> +	struct msm_vidc_inst *inst;
> +	int rc = 0;
> +
> +	inst = container_of(fh, struct msm_vidc_inst, fh);
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !sub) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_subscribe_event((void *)inst, sub);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
> +			       const struct v4l2_event_subscription *sub)
> +{
> +	struct msm_vidc_inst *inst;
> +	int rc = 0;
> +
> +	inst = container_of(fh, struct msm_vidc_inst, fh);
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !sub) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_unsubscribe_event((void *)inst, sub);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh,
> +			     struct v4l2_decoder_cmd *dec)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !dec) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
> +			 struct v4l2_decoder_cmd *dec)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	enum msm_vidc_event event;
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	if (!dec) {
> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	if (dec->cmd != V4L2_DEC_CMD_START &&
> +	    dec->cmd != V4L2_DEC_CMD_STOP) {
> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
> +	rc = inst->event_handle(inst, event, NULL);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh,
> +			     struct v4l2_encoder_cmd *enc)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !enc) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
> +			 struct v4l2_encoder_cmd *enc)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	enum msm_vidc_event event;
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	if (!enc) {
> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	if (enc->cmd != V4L2_ENC_CMD_START &&
> +	    enc->cmd != V4L2_ENC_CMD_STOP) {
> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
> +	rc = inst->event_handle(inst, event, NULL);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_framesizes(struct file *filp, void *fh,
> +			     struct v4l2_frmsizeenum *fsize)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !fsize) {
> +		d_vpr_e("%s: invalid params: %pK %pK\n",
> +			__func__, inst, fsize);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_framesizes((void *)inst, fsize);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_frameintervals(struct file *filp, void *fh,
> +				 struct v4l2_frmivalenum *fival)
> +
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !fival) {
> +		d_vpr_e("%s: invalid params: %pK %pK\n",
> +			__func__, inst, fival);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_frameintervals((void *)inst, fival);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_queryctrl(struct file *filp, void *fh,
> +		       struct v4l2_queryctrl *ctrl)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !ctrl) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_query_ctrl((void *)inst, ctrl);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_querymenu(struct file *filp, void *fh,
> +		       struct v4l2_querymenu *qmenu)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !qmenu) {
> +		d_vpr_e("%s: invalid params %pK %pK\n",
> +			__func__, inst, qmenu);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_query_menu((void *)inst, qmenu);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +void msm_v4l2_m2m_device_run(void *priv)
> +{
> +	d_vpr_l("%s(): device_run\n", __func__);
> +}
> +
> +void msm_v4l2_m2m_job_abort(void *priv)
> +{
> +	struct msm_vidc_inst *inst = priv;
> +
> +	if (!inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +	i_vpr_h(inst, "%s: m2m job aborted\n", __func__);
> +	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
> +}

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
@ 2023-07-28 13:45   ` Konrad Dybcio
  2023-08-14 18:49     ` Dikshita Agarwal
  2023-07-28 13:47   ` Konrad Dybcio
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 13:45 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the platform driver methods, file
> operations and v4l2 registration.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
[...]

> +struct msm_vidc_core *g_core;
> +
> +static inline bool is_video_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
> +}
Are you expecting this to be expanded each time support for new SoC is added?

> +
> +static inline bool is_video_context_bank_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
> +}
> +
> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
> +{
> +	struct msm_vidc_resource *res = NULL;
No need to initialize, you use it right after defining.

> +	int rc = 0;
I think 'ret' is more common for a return-value-holding variable.

> +
> +	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
> +	if (!res) {
> +		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
> +		return -ENOMEM;
> +	}
> +	core->resource = res;
I don't think the 'res' variable makes sense.

> +
> +	rc = call_res_op(core, init, core);
> +	if (rc) {
> +		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
> +		return rc;
you can omit this line and return rc/ret at the last line of this func.

> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id msm_vidc_dt_match[] = {
> +	{.compatible = "qcom,sm8550-vidc"},
{ .compatible = .... " },

> +	{.compatible = "qcom,vidc,cb-ns"},
> +	MSM_VIDC_EMPTY_BRACE
why?

> +};
> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
> +
> +static void msm_vidc_release_video_device(struct video_device *vdev)
> +{
> +	d_vpr_e("%s: video device released\n", __func__);
> +}
Doesn't sound too useful? And definitely not with an error print?

> +
> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
> +					     enum msm_vidc_domain_type type)
> +{
> +	int index;
> +
> +	if (type == MSM_VIDC_DECODER)
I'm not sure this is defined.

> +		index = 0;
> +	else if (type == MSM_VIDC_ENCODER)
Or this.

Can't we just assign index = MSM_VIDC_EN/DECODER?

> +		index = 1;
> +	else
> +		return;
> +
> +	v4l2_m2m_release(core->vdev[index].m2m_dev);
> +
> +	video_set_drvdata(&core->vdev[index].vdev, NULL);
> +	video_unregister_device(&core->vdev[index].vdev);
> +}
> +
> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
> +					  enum msm_vidc_domain_type type, int nr)
> +{
> +	int rc = 0;
> +	int index;
> +
> +	d_vpr_h("%s: domain %d\n", __func__, type);
> +
> +	if (type == MSM_VIDC_DECODER)
> +		index = 0;
> +	else if (type == MSM_VIDC_ENCODER)
> +		index = 1;
> +	else
> +		return -EINVAL;
> +
> +	core->vdev[index].vdev.release =
> +		msm_vidc_release_video_device;
> +	core->vdev[index].vdev.fops = core->v4l2_file_ops;
> +	if (type == MSM_VIDC_DECODER)
> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
> +	else
> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
> +	core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
> +	core->vdev[index].type = type;
> +	core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
> +	core->vdev[index].vdev.device_caps = core->capabilities[DEVICE_CAPS].value;
> +	rc = video_register_device(&core->vdev[index].vdev,
> +				   VFL_TYPE_VIDEO, nr);
> +	if (rc) {
> +		d_vpr_e("Failed to register the video device\n");
> +		return rc;
> +	}
> +	video_set_drvdata(&core->vdev[index].vdev, core);
> +
> +	core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
> +	if (IS_ERR(core->vdev[index].m2m_dev)) {
> +		d_vpr_e("Failed to initialize V4L2 M2M device\n");
> +		rc = PTR_ERR(core->vdev[index].m2m_dev);
> +		goto m2m_init_failed;
> +	}
> +
> +	return 0;
> +
> +m2m_init_failed:
> +	video_unregister_device(&core->vdev[index].vdev);
> +	return rc;
> +}
> +
> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
> +{
> +	int rc = 0;
> +
> +	if (!core) {
Are we expecting to ever hit this?

> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	mutex_destroy(&core->lock);
> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
Not defined.

> +
> +	if (core->batch_workq)
> +		destroy_workqueue(core->batch_workq);
> +
> +	if (core->pm_workq)
> +		destroy_workqueue(core->pm_workq);
> +
> +	core->batch_workq = NULL;
> +	core->pm_workq = NULL;
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
> +{
> +	int rc = 0;
> +
> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
Not defined.

> +
> +	core->pm_workq = create_singlethread_workqueue("pm_workq");
> +	if (!core->pm_workq) {
> +		d_vpr_e("%s: create pm workq failed\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	core->batch_workq = create_singlethread_workqueue("batch_workq");
> +	if (!core->batch_workq) {
> +		d_vpr_e("%s: create batch workq failed\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
> +	core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
> +	if (!core->packet) {
> +		d_vpr_e("%s: failed to alloc core packet\n", __func__);
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	core->response_packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
> +	if (!core->packet) {
> +		d_vpr_e("%s: failed to alloc core response packet\n", __func__);
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	mutex_init(&core->lock);
> +	INIT_LIST_HEAD(&core->instances);
> +	INIT_LIST_HEAD(&core->dangling_instances);
> +
> +	INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
> +	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
> +
> +	return 0;
Either return rc/ret here or don't initialize it at definition.

> +exit:
> +	if (core->batch_workq)
> +		destroy_workqueue(core->batch_workq);
> +	if (core->pm_workq)
> +		destroy_workqueue(core->pm_workq);
> +	core->batch_workq = NULL;
> +	core->pm_workq = NULL;
> +
> +	return rc;
> +}
[...]

> +
> +static int msm_vidc_pm_suspend(struct device *dev)
> +{
> +	int rc = 0;
> +	struct msm_vidc_core *core;
> +	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
> +
> +	/*
> +	 * Bail out if
> +	 * - driver possibly not probed yet
Would the pm callbacks be registered by then?

> +	 * - not the main device. We don't support power management on
> +	 *   subdevices (e.g. context banks)
I'm not sure registering context banks as different kinds of devices
within the same driver is a good idea, this seems rather convoluted.

> +	 */
> +	if (!dev || !dev->driver || !is_video_device(dev))
> +		return 0;
> +
> +	core = dev_get_drvdata(dev);
> +	if (!core) {
> +		d_vpr_e("%s: invalid core\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	core_lock(core, __func__);
> +	allow = msm_vidc_allow_pm_suspend(core);
> +
> +	if (allow == MSM_VIDC_IGNORE) {
> +		d_vpr_h("%s: pm already suspended\n", __func__);
> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +		rc = 0;
> +		goto unlock;
> +	} else if (allow != MSM_VIDC_ALLOW) {
> +		d_vpr_h("%s: pm suspend not allowed\n", __func__);
> +		rc = 0;
> +		goto unlock;
> +	}
> +
> +	rc = msm_vidc_suspend(core);
> +	if (rc == -EOPNOTSUPP)
> +		rc = 0;
> +	else if (rc)
> +		d_vpr_e("Failed to suspend: %d\n", rc);
> +	else
> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +
> +unlock:
> +	core_unlock(core, __func__);
> +	return rc;
> +}
> +
> +static int msm_vidc_pm_resume(struct device *dev)
Same comments as in _suspend

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
  2023-07-28 13:45   ` Konrad Dybcio
@ 2023-07-28 13:47   ` Konrad Dybcio
  2023-07-28 13:49   ` Dmitry Baryshkov
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 13:47 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the platform driver methods, file
> operations and v4l2 registration.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660 +++++++++++++++++++++
Moreover, this code is never compiled.

Sending dead code is almost always wrong.

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
  2023-07-28 13:45   ` Konrad Dybcio
  2023-07-28 13:47   ` Konrad Dybcio
@ 2023-07-28 13:49   ` Dmitry Baryshkov
  2023-08-14 18:58     ` Dikshita Agarwal
  2023-07-31 21:16   ` Krzysztof Kozlowski
  2023-07-31 21:23   ` Krzysztof Kozlowski
  4 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 13:49 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the platform driver methods, file
> operations and v4l2 registration.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660 +++++++++++++++++++++
>   1 file changed, 660 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> new file mode 100644
> index 0000000..43439cb
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> @@ -0,0 +1,660 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iommu.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/stringify.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_memory.h"
> +#include "msm_vidc_platform.h"
> +#include "msm_vidc_state.h"
> +#include "venus_hfi.h"

This files are not present yet, so this commit doesn't have a change of 
being compiled in any way.

> +
> +#define BASE_DEVICE_NUMBER 32
> +
> +struct msm_vidc_core *g_core;
> +
> +static inline bool is_video_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));

Are you going to add future platforms to this list? Please don't 
duplicate of_match_data here.

> +}
> +
> +static inline bool is_video_context_bank_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
> +}
> +
> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
> +{
> +	struct msm_vidc_resource *res = NULL;
> +	int rc = 0;
> +
> +	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
> +	if (!res) {
> +		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);

Where is this macro defined? Please structure your comments in a logical 
way, so that one can read them from the beginning and understand what is 
going one.

This is not to mention that adding such debugging wrappers doesn't have 
a lot of value.

> +		return -ENOMEM;
> +	}
> +	core->resource = res;
> +
> +	rc = call_res_op(core, init, core);

What is call_res_op?

> +	if (rc) {
> +		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id msm_vidc_dt_match[] = {
> +	{.compatible = "qcom,sm8550-vidc"},
> +	{.compatible = "qcom,vidc,cb-ns"},
> +	MSM_VIDC_EMPTY_BRACE

NO!!! Please use {} directly.

> +};
> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
> +
> +static void msm_vidc_release_video_device(struct video_device *vdev)
> +{
> +	d_vpr_e("%s: video device released\n", __func__);
> +}
> +
> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
> +					     enum msm_vidc_domain_type type)
> +{
> +	int index;
> +
> +	if (type == MSM_VIDC_DECODER)
> +		index = 0;
> +	else if (type == MSM_VIDC_ENCODER)
> +		index = 1;
> +	else
> +		return;

You can index by the type instead of converting to index.

> +
> +	v4l2_m2m_release(core->vdev[index].m2m_dev);
> +
> +	video_set_drvdata(&core->vdev[index].vdev, NULL);
> +	video_unregister_device(&core->vdev[index].vdev);
> +}
> +
> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
> +					  enum msm_vidc_domain_type type, int nr)
> +{
> +	int rc = 0;
> +	int index;
> +
> +	d_vpr_h("%s: domain %d\n", __func__, type);
> +
> +	if (type == MSM_VIDC_DECODER)
> +		index = 0;
> +	else if (type == MSM_VIDC_ENCODER)
> +		index = 1;
> +	else
> +		return -EINVAL;
> +
> +	core->vdev[index].vdev.release =
> +		msm_vidc_release_video_device;
> +	core->vdev[index].vdev.fops = core->v4l2_file_ops;
> +	if (type == MSM_VIDC_DECODER)
> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
> +	else
> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
> +	core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
> +	core->vdev[index].type = type;
> +	core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
> +	core->vdev[index].vdev.device_caps = core->capabilities[DEVICE_CAPS].value;
> +	rc = video_register_device(&core->vdev[index].vdev,
> +				   VFL_TYPE_VIDEO, nr);
> +	if (rc) {
> +		d_vpr_e("Failed to register the video device\n");
> +		return rc;
> +	}
> +	video_set_drvdata(&core->vdev[index].vdev, core);
> +
> +	core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
> +	if (IS_ERR(core->vdev[index].m2m_dev)) {
> +		d_vpr_e("Failed to initialize V4L2 M2M device\n");
> +		rc = PTR_ERR(core->vdev[index].m2m_dev);
> +		goto m2m_init_failed;
> +	}
> +
> +	return 0;
> +
> +m2m_init_failed:
> +	video_unregister_device(&core->vdev[index].vdev);
> +	return rc;
> +}
> +
> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
> +{
> +	int rc = 0;
> +
> +	if (!core) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	mutex_destroy(&core->lock);
> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> +
> +	if (core->batch_workq)
> +		destroy_workqueue(core->batch_workq);
> +
> +	if (core->pm_workq)
> +		destroy_workqueue(core->pm_workq);
> +
> +	core->batch_workq = NULL;
> +	core->pm_workq = NULL;
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
> +{
> +	int rc = 0;
> +
> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> +
> +	core->pm_workq = create_singlethread_workqueue("pm_workq");
> +	if (!core->pm_workq) {
> +		d_vpr_e("%s: create pm workq failed\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	core->batch_workq = create_singlethread_workqueue("batch_workq");
> +	if (!core->batch_workq) {
> +		d_vpr_e("%s: create batch workq failed\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
> +	core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
> +	if (!core->packet) {
> +		d_vpr_e("%s: failed to alloc core packet\n", __func__);
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	core->response_packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
> +	if (!core->packet) {
> +		d_vpr_e("%s: failed to alloc core response packet\n", __func__);
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	mutex_init(&core->lock);
> +	INIT_LIST_HEAD(&core->instances);
> +	INIT_LIST_HEAD(&core->dangling_instances);
> +
> +	INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
> +	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
> +
> +	return 0;
> +exit:
> +	if (core->batch_workq)
> +		destroy_workqueue(core->batch_workq);
> +	if (core->pm_workq)
> +		destroy_workqueue(core->pm_workq);
> +	core->batch_workq = NULL;
> +	core->pm_workq = NULL;
> +
> +	return rc;
> +}
> +
> +static void msm_vidc_devm_deinit_core(void *res)
> +{
> +	struct msm_vidc_core *core = res;
> +
> +	msm_vidc_deinitialize_core(core);
> +}
> +
> +static int msm_vidc_devm_init_core(struct device *dev, struct msm_vidc_core *core)
> +{
> +	int rc = 0;
> +
> +	if (!dev || !core) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_initialize_core(core);
> +	if (rc) {
> +		d_vpr_e("%s: init failed with %d\n", __func__, rc);
> +		return rc;
> +	}
> +
> +	rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void *)core);
> +	if (rc)
> +		return -EINVAL;
> +
> +	return rc;
> +}
> +
> +static void msm_vidc_devm_debugfs_put(void *res)
> +{
> +	struct dentry *parent = res;
> +
> +	debugfs_remove_recursive(parent);
> +}
> +
> +static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev)

Why is it called get?


> +{
> +	struct dentry *parent = NULL;
> +	int rc = 0;
> +
> +	if (!dev) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return NULL;
> +	}
> +
> +	parent = msm_vidc_debugfs_init_drv();
> +	if (!parent)
> +		return NULL;
> +
> +	rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void *)parent);
> +	if (rc)
> +		return NULL;
> +
> +	return parent;
> +}
> +
> +static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
> +				       struct device *dev)
> +{
> +	struct context_bank_info *cb = NULL;
> +	int rc = 0;
> +
> +	cb = msm_vidc_get_context_bank_for_device(core, dev);
> +	if (!cb) {
> +		d_vpr_e("%s: Failed to get context bank device for %s\n",
> +			__func__, dev_name(dev));
> +		return -EIO;
> +	}
> +
> +	/* populate dev & domain field */
> +	cb->dev = dev;
> +	cb->domain = iommu_get_domain_for_dev(cb->dev);
> +	if (!cb->domain) {
> +		d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__, dev_name(dev));
> +		return -EIO;
> +	}
> +
> +	if (cb->dma_mask) {
> +		rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask);
> +		if (rc) {
> +			d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__);
> +			return rc;
> +		}
> +	}
> +
> +	/*
> +	 * configure device segment size and segment boundary to ensure
> +	 * iommu mapping returns one mapping (which is required for partial
> +	 * cache operations)
> +	 */
> +	if (!dev->dma_parms)
> +		dev->dma_parms =
> +			devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
> +	dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
> +	dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
> +
> +	iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler, (void *)core);
> +
> +	d_vpr_h("%s: name %s addr start %x size %x secure %d\n",
> +		__func__, cb->name, cb->addr_range.start,
> +		cb->addr_range.size, cb->secure);
> +	d_vpr_h("%s: dma_coherant %d region %d dev_name %s domain %pK dma_mask %llu\n",
> +		__func__, cb->dma_coherant, cb->region, dev_name(cb->dev),
> +		cb->domain, cb->dma_mask);
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_remove_video_device(struct platform_device *pdev)
> +{
> +	struct msm_vidc_core *core;
> +
> +	if (!pdev) {
> +		d_vpr_e("%s: invalid input %pK", __func__, pdev);
> +		return -EINVAL;
> +	}
> +
> +	core = dev_get_drvdata(&pdev->dev);
> +	if (!core) {
> +		d_vpr_e("%s: invalid core\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	msm_vidc_core_deinit(core, true);
> +	venus_hfi_queue_deinit(core);
> +
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> +
> +	v4l2_device_unregister(&core->v4l2_dev);
> +
> +	d_vpr_h("depopulating sub devices\n");
> +	/*
> +	 * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx
> +	 * When msm_vidc_remove is called for each sub-device, destroy
> +	 * context-bank mappings.
> +	 */
> +	of_platform_depopulate(&pdev->dev);
> +
> +	dev_set_drvdata(&pdev->dev, NULL);
> +	g_core = NULL;
> +	d_vpr_h("%s(): succssful\n", __func__);
> +
> +	return 0;
> +}
> +
> +static int msm_vidc_remove_context_bank(struct platform_device *pdev)
> +{
> +	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
> +
> +	return 0;
> +}
> +
> +static int msm_vidc_remove(struct platform_device *pdev)
> +{
> +	/*
> +	 * Sub devices remove will be triggered by of_platform_depopulate()
> +	 * after core_deinit(). It return immediately after completing
> +	 * sub-device remove.
> +	 */
> +	if (is_video_device(&pdev->dev))
> +		return msm_vidc_remove_video_device(pdev);
> +	else if (is_video_context_bank_device(&pdev->dev))
> +		return msm_vidc_remove_context_bank(pdev);
> +
> +	/* How did we end up here? */
> +	WARN_ON(1);
> +	return -EINVAL;
> +}
> +
> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
> +{
> +	int rc = 0;
> +	struct msm_vidc_core *core = NULL;
> +	int nr = BASE_DEVICE_NUMBER;
> +
> +	d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
> +
> +	core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL);
> +	if (!core) {
> +		d_vpr_e("%s: failed to alloc memory for core\n", __func__);
> +		return -ENOMEM;
> +	}
> +	g_core = core;
> +
> +	core->pdev = pdev;
> +	dev_set_drvdata(&pdev->dev, core);
> +
> +	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
> +	if (!core->debugfs_parent)
> +		d_vpr_h("Failed to create debugfs for msm_vidc\n");
> +
> +	rc = msm_vidc_devm_init_core(&pdev->dev, core);
> +	if (rc) {
> +		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
> +		goto init_core_failed;
> +	}
> +
> +	rc = msm_vidc_init_platform(core);
> +	if (rc) {
> +		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
> +		rc = -EINVAL;
> +		goto init_plat_failed;
> +	}
> +
> +	rc = msm_vidc_init_resources(core);
> +	if (rc) {
> +		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
> +		goto init_res_failed;
> +	}
> +
> +	rc = msm_vidc_init_core_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
> +		goto init_res_failed;
> +	}
> +
> +	rc = msm_vidc_init_instance_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
> +		goto init_inst_caps_fail;
> +	}
> +
> +	core->debugfs_root = msm_vidc_debugfs_init_core(core);
> +	if (!core->debugfs_root)
> +		d_vpr_h("Failed to init debugfs core\n");
> +
> +	d_vpr_h("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.
> +	 */
> +	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
> +				  &pdev->dev);
> +	if (rc) {
> +		d_vpr_e("Failed to trigger probe for sub-devices\n");
> +		goto sub_dev_failed;
> +	}
> +
> +	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
> +	if (rc) {
> +		d_vpr_e("Failed to register v4l2 device\n");
> +		goto v4l2_reg_failed;
> +	}
> +
> +	/* setup the decoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
> +	if (rc) {
> +		d_vpr_e("Failed to register video decoder\n");
> +		goto dec_reg_failed;
> +	}
> +
> +	/* setup the encoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
> +	if (rc) {
> +		d_vpr_e("Failed to register video encoder\n");
> +		goto enc_reg_failed;
> +	}
> +
> +	rc = venus_hfi_queue_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: interface queues init failed\n", __func__);
> +		goto queues_init_failed;
> +	}
> +
> +	rc = msm_vidc_core_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: sys init failed\n", __func__);
> +		goto core_init_failed;
> +	}
> +
> +	d_vpr_h("%s(): succssful\n", __func__);
> +
> +	return rc;
> +
> +core_init_failed:
> +	venus_hfi_queue_deinit(core);
> +queues_init_failed:
> +	of_platform_depopulate(&pdev->dev);
> +sub_dev_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> +enc_reg_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> +dec_reg_failed:
> +	v4l2_device_unregister(&core->v4l2_dev);
> +v4l2_reg_failed:
> +init_inst_caps_fail:
> +init_res_failed:
> +init_plat_failed:
> +init_core_failed:
> +	dev_set_drvdata(&pdev->dev, NULL);
> +	g_core = NULL;
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
> +{
> +	struct msm_vidc_core *core = NULL;
> +	int rc = 0;
> +
> +	if (!pdev) {
> +		d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
> +		return -EINVAL;
> +	} else if (!pdev->dev.parent) {
> +		d_vpr_e("%s: Failed to find a parent for %s\n",
> +			__func__, dev_name(&pdev->dev));
> +		return -ENODEV;
> +	}
> +
> +	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
> +
> +	core = dev_get_drvdata(pdev->dev.parent);
> +	if (!core) {
> +		d_vpr_e("%s: core not found in device %s",
> +			__func__, dev_name(pdev->dev.parent));
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_setup_context_bank(core, &pdev->dev);
> +	if (rc) {
> +		d_vpr_e("%s: Failed to probe context bank %s\n",
> +			__func__, dev_name(&pdev->dev));
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_probe(struct platform_device *pdev)
> +{
> +	if (!pdev) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * 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 (is_video_device(&pdev->dev))
> +		return msm_vidc_probe_video_device(pdev);
> +	else if (is_video_context_bank_device(&pdev->dev))
> +		return msm_vidc_probe_context_bank(pdev);
> +
> +	/* How did we end up here? */
> +	WARN_ON(1);
> +	return -EINVAL;

No. Please don't hack around the driver infrastructure and register two 
separate drivers. They can even come in two separate commits, 
simplifying the review.

> +}
> +
> +static int msm_vidc_pm_suspend(struct device *dev)
> +{
> +	int rc = 0;
> +	struct msm_vidc_core *core;
> +	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
> +
> +	/*
> +	 * Bail out if
> +	 * - driver possibly not probed yet
> +	 * - not the main device. We don't support power management on
> +	 *   subdevices (e.g. context banks)
> +	 */
> +	if (!dev || !dev->driver || !is_video_device(dev))
> +		return 0;
> +
> +	core = dev_get_drvdata(dev);
> +	if (!core) {
> +		d_vpr_e("%s: invalid core\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	core_lock(core, __func__);
> +	allow = msm_vidc_allow_pm_suspend(core);
> +
> +	if (allow == MSM_VIDC_IGNORE) {
> +		d_vpr_h("%s: pm already suspended\n", __func__);
> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +		rc = 0;
> +		goto unlock;
> +	} else if (allow != MSM_VIDC_ALLOW) {
> +		d_vpr_h("%s: pm suspend not allowed\n", __func__);
> +		rc = 0;
> +		goto unlock;
> +	}
> +
> +	rc = msm_vidc_suspend(core);
> +	if (rc == -EOPNOTSUPP)
> +		rc = 0;
> +	else if (rc)
> +		d_vpr_e("Failed to suspend: %d\n", rc);
> +	else
> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +
> +unlock:
> +	core_unlock(core, __func__);
> +	return rc;
> +}
> +
> +static int msm_vidc_pm_resume(struct device *dev)
> +{
> +	struct msm_vidc_core *core;
> +
> +	/*
> +	 * Bail out if
> +	 * - driver possibly not probed yet
> +	 * - not the main device. We don't support power management on
> +	 *   subdevices (e.g. context banks)
> +	 */
> +	if (!dev || !dev->driver || !is_video_device(dev))
> +		return 0;
> +
> +	core = dev_get_drvdata(dev);
> +	if (!core) {
> +		d_vpr_e("%s: invalid core\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* remove PM suspend from core sub_state */
> +	core_lock(core, __func__);
> +	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
> +	core_unlock(core, __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)

No runtime PM?

> +};
> +
> +struct platform_driver msm_vidc_driver = {
> +	.probe = msm_vidc_probe,
> +	.remove = msm_vidc_remove,
> +	.driver = {
> +		.name = "msm_vidc_v4l2",
> +		.of_match_table = msm_vidc_dt_match,
> +		.pm = &msm_vidc_pm_ops,
> +	},
> +};
> +
> +module_platform_driver(msm_vidc_driver);
> +MODULE_LICENSE("GPL");

Unfortunately, after taking a glance at first two patches, I have to 
stop. It is nearly impossible to review it.

Please start from the beginning, split the driver according to the 
logical functions, not per-file. Ideally something should be compillable 
starting from one of the first patches, if not the very first one. This 
would guarantee that your patchset is structured logically.

Please add DT bindings. New driver series should start from the bindings 
anyway.

Please drop your custom debugging wrappers. Use dev_info, dev_warn, 
dev_err and dev_dbg instead.

Please drop the custom multi-device-single-driver scheme. If there are 
different kinds of devices, there should be different drivers.

Please take a look around. If you are pushing your driver for kernel 
inclusion, it should not stand out by the style and by the typical code 
seuqences.


-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (33 preceding siblings ...)
  2023-07-28 13:32 ` [PATCH 00/33] Qualcomm video decoder/encoder driver Dmitry Baryshkov
@ 2023-07-28 14:01 ` Dmitry Baryshkov
  2023-08-14 12:58   ` Stanimir Varbanov
  2023-07-28 14:34 ` Bryan O'Donoghue
  35 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 14:01 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> This patch series introduces support for Qualcomm new video acceleration
> hardware architecture, used for video stream decoding/encoding. This driver
> is based on new communication protocol between video hardware and application
> processor.
> 
> This driver comes with below capabilities:
> - V4L2 complaint video driver with M2M and STREAMING capability.
> - Supports H264, H265, VP9 decoders.
> - Supports H264, H265 encoders.

Please describe, why is it impossible to support this hardware in the 
venus driver. We do not usually add new drivers for the new generations 
of the hardware, unless it is fully incompatible with the previous 
generations. Let me point you to camss or drm/msm drivers. They have 
successfully solved the issue of supporting multiple generations of the 
hardware in the same driver.

Unless the "iris3" is completely different from all the previous 
generations, I strongly suggest spending time on restructuring existing 
venus driver and then adding support for the new hardware there instead 
of dumping out something completely new.

> 
> This driver comes with below features:
> - Centralized resource and memory management.
> - Centralized management of core and instance states.
> - Defines platform specific capabilities and features. As a results, it provides
>    a single point of control to enable/disable a given feature depending on
>    specific platform capabilities.
> - Handles hardware interdependent configurations. For a given configuration from
>    client, the driver checks for hardware dependent configuration/s and updates
>    the same.
> - Handles multiple complex video scenarios involving state transitions - DRC,
>    Drain, Seek, back to back DRC, DRC during Drain sequence, DRC during Seek
>    sequence.
> - Introduces a flexible way for driver to subscribe for any property with
>    hardware. Hardware would inform driver with those subscribed property with any
>    change in value.
> - Introduces performance (clock and bus) model based on new hardware
>    architecture.
> - Introduces multi thread safe design to handle communication between client and
>    hardware.
> - Adapts encoder quality improvements available in new hardware architecture.
> - Implements asynchronous communication with hardware to achieve better
>    experience in low latency usecases.
> - Supports multi stage hardware architecture for encode/decode.
> - Output and capture planes are controlled independently. Thereby providing a
>    way to reconfigure individual plane.
> - Hardware packetization layer supports synchronization between configuration
>    packet and data packet.
> - Introduces a flexibility to receive a hardware response for a given command
>    packet.
> - Native hardware support of LAST flag which is mandatory to align with port
>    reconfiguration and DRAIN sequence as per V4L guidelines.
> - Native hardware support for drain sequence.
> 
> I think that the driver is in good shape for mainline kernel, and I hope the
> review comments will help to improve it, so please do review, and make comments.
> 
> Dikshita Agarwal (17):
>    iris: vidc: add core functions
>    iris: add vidc wrapper file
>    iris: vidc: add vb2 ops
>    iris: vidc: add helpers for memory management
>    iris: vidc: add helper functions for resource management
>    iris: vidc: add helper functions for power management
>    iris: add helpers for media format
>    iris: vidc: add PIL functionality for video firmware
>    iris: platform: add platform files
>    iris: platform: sm8550: add capability file for sm8550
>    iris: variant: add helper functions for register handling
>    iris: variant: iris3: add iris3 specific ops
>    iris: variant: iris3: add helpers for buffer size calculations
>    iris: variant: iris3: add helper for bus and clock calculation
>    iris: variant: iris: implement the logic to compute bus bandwidth
>    iris: variant: iris3: implement logic to compute clock frequency
>    iris: enable building of iris video driver
> 
> Vikash Garodia (16):
>    MAINTAINERS: Add Qualcomm Iris video accelerator driver
>    iris: vidc: add v4l2 wrapper file
>    iris: vidc: define video core and instance context
>    iris: iris: add video encoder files
>    iris: vidc: add video decoder files
>    iris: vidc: add control files
>    iris: vidc: add helper functions
>    iris: vidc: add helpers for state management
>    iris: add vidc buffer files
>    iris: vidc: define various structures and enum
>    iris: vidc: hfi: add Host Firmware Interface (HFI)
>    iris: vidc: hfi: add Host Firmware Interface (HFI) response handling
>    iris: vidc: hfi: add helpers for handling shared queues
>    iris: vidc: hfi: Add packetization layer
>    iris: vidc: hfi: defines HFI properties and enums
>    iris: vidc: add debug files
> 
>   MAINTAINERS                                        |   10 +
>   drivers/media/platform/qcom/Kconfig                |    1 +
>   drivers/media/platform/qcom/Makefile               |    1 +
>   drivers/media/platform/qcom/iris/Kconfig           |   15 +
>   drivers/media/platform/qcom/iris/Makefile          |   46 +
>   .../iris/platform/common/inc/msm_vidc_platform.h   |  305 ++
>   .../iris/platform/common/src/msm_vidc_platform.c   | 2499 ++++++++++++
>   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
>   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++
>   .../iris/variant/common/inc/msm_vidc_variant.h     |   22 +
>   .../iris/variant/common/src/msm_vidc_variant.c     |  163 +
>   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 +++++++
>   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
>   .../qcom/iris/variant/iris3/inc/msm_vidc_iris3.h   |   15 +
>   .../iris/variant/iris3/inc/msm_vidc_power_iris3.h  |   17 +
>   .../iris/variant/iris3/inc/perf_static_model.h     |  229 ++
>   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 +++
>   .../iris/variant/iris3/src/msm_vidc_bus_iris3.c    |  884 ++++
>   .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  |  627 +++
>   .../qcom/iris/variant/iris3/src/msm_vidc_iris3.c   |  954 +++++
>   .../iris/variant/iris3/src/msm_vidc_power_iris3.c  |  345 ++
>   .../media/platform/qcom/iris/vidc/inc/firmware.h   |   18 +
>   .../platform/qcom/iris/vidc/inc/hfi_command.h      |  190 +
>   .../media/platform/qcom/iris/vidc/inc/hfi_packet.h |   52 +
>   .../platform/qcom/iris/vidc/inc/hfi_property.h     |  666 +++
>   .../platform/qcom/iris/vidc/inc/msm_media_info.h   |  599 +++
>   .../media/platform/qcom/iris/vidc/inc/msm_vdec.h   |   40 +
>   .../media/platform/qcom/iris/vidc/inc/msm_venc.h   |   34 +
>   .../media/platform/qcom/iris/vidc/inc/msm_vidc.h   |   60 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_buffer.h  |   32 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_control.h |   26 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_core.h    |  165 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   |  186 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_driver.h  |  352 ++
>   .../platform/qcom/iris/vidc/inc/msm_vidc_inst.h    |  207 +
>   .../qcom/iris/vidc/inc/msm_vidc_internal.h         |  787 ++++
>   .../platform/qcom/iris/vidc/inc/msm_vidc_memory.h  |   83 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_power.h   |   94 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_state.h   |  102 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |   77 +
>   .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |   39 +
>   .../media/platform/qcom/iris/vidc/inc/resources.h  |  259 ++
>   .../media/platform/qcom/iris/vidc/inc/venus_hfi.h  |   66 +
>   .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |   89 +
>   .../qcom/iris/vidc/inc/venus_hfi_response.h        |   26 +
>   .../media/platform/qcom/iris/vidc/src/firmware.c   |  294 ++
>   .../media/platform/qcom/iris/vidc/src/hfi_packet.c |  657 +++
>   .../media/platform/qcom/iris/vidc/src/msm_vdec.c   | 2091 ++++++++++
>   .../media/platform/qcom/iris/vidc/src/msm_venc.c   | 1484 +++++++
>   .../media/platform/qcom/iris/vidc/src/msm_vidc.c   |  841 ++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_buffer.c  |  290 ++
>   .../platform/qcom/iris/vidc/src/msm_vidc_control.c |  824 ++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   |  581 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_driver.c  | 4276 ++++++++++++++++++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_memory.c  |  448 ++
>   .../platform/qcom/iris/vidc/src/msm_vidc_power.c   |  560 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   |  660 +++
>   .../platform/qcom/iris/vidc/src/msm_vidc_state.c   | 1607 ++++++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    |  953 +++++
>   .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     |  605 +++
>   .../media/platform/qcom/iris/vidc/src/resources.c  | 1321 ++++++
>   .../media/platform/qcom/iris/vidc/src/venus_hfi.c  | 1503 +++++++
>   .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  |  537 +++
>   .../qcom/iris/vidc/src/venus_hfi_response.c        | 1607 ++++++++
>   64 files changed, 35357 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/Kconfig
>   create mode 100644 drivers/media/platform/qcom/iris/Makefile
>   create mode 100644 drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
>   create mode 100644 drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/firmware.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/resources.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/firmware.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/resources.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
>   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c
> 

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550
  2023-07-28 13:23 ` [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550 Vikash Garodia
@ 2023-07-28 14:13   ` Dmitry Baryshkov
  2023-08-14 19:35     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 14:13 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements all the capabilities supported by sm8550.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
>   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++++++++++++++
>   2 files changed, 1741 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> 
> diff --git a/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> new file mode 100644
> index 0000000..0a2f172
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_SM8550_H_
> +#define _MSM_VIDC_SM8550_H_
> +
> +#include "msm_vidc_core.h"
> +
> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core);
> +
> +#endif // _MSM_VIDC_SM8550_H_
> diff --git a/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> new file mode 100644
> index 0000000..2408556
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> @@ -0,0 +1,1727 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <dt-bindings/clock/qcom,sm8550-gcc.h>
> +#include <dt-bindings/clock/qcom,sm8450-videocc.h>
> +
> +#include "hfi_command.h"
> +#include "hfi_property.h"
> +#include "msm_vidc_control.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_iris3.h"
> +#include "msm_vidc_sm8550.h"
> +#include "msm_vidc_platform.h"
> +
> +/* version: major[24:31], minor[16:23], revision[0:15] */
> +#define DRIVER_VERSION          0x04000000
> +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
> +#define MAX_BASE_LAYER_PRIORITY_ID 63
> +#define MAX_OP_POINT            31
> +#define MAX_BITRATE             245000000
> +#define DEFAULT_BITRATE         20000000
> +#define MINIMUM_FPS             1
> +#define MAXIMUM_FPS             480
> +#define MAXIMUM_DEC_FPS         960
> +#define MAX_QP                  51
> +#define DEFAULT_QP              20
> +#define MAX_CONSTANT_QUALITY    100
> +#define MIN_SLICE_BYTE_SIZE     512
> +#define MAX_SLICE_BYTE_SIZE       \
> +	((MAX_BITRATE) >> 3)
> +#define MAX_SLICE_MB_SIZE         \
> +	(((4096 + 15) >> 4) * ((2304 + 15) >> 4))
> +
> +#define ENC     MSM_VIDC_ENCODER
> +#define DEC     MSM_VIDC_DECODER
> +#define H264    MSM_VIDC_H264
> +#define HEVC    MSM_VIDC_HEVC
> +#define VP9     MSM_VIDC_VP9

Another redefinition. Inline it.

> +#define CODECS_ALL     (H264 | HEVC | VP9)
> +#define MAXIMUM_OVERRIDE_VP9_FPS 200
> +
> +static struct codec_info codec_data_sm8550[] = {
> +	{
> +		.v4l2_codec  = V4L2_PIX_FMT_H264,
> +		.vidc_codec  = MSM_VIDC_H264,
> +		.pixfmt_name = "AVC",

Have you considered using existing code which enumerates formats? For 
example, it is much better to refactor v4l_fill_fmtdesc() to allow 
getting the description instead of adding your own names here.
Not to mention that printk supports %p4cc for printing fourcc values. I 
hope you knew that.

> +	},
> +	{
> +		.v4l2_codec  = V4L2_PIX_FMT_HEVC,
> +		.vidc_codec  = MSM_VIDC_HEVC,
> +		.pixfmt_name = "HEVC",
> +	},
> +	{
> +		.v4l2_codec  = V4L2_PIX_FMT_VP9,
> +		.vidc_codec  = MSM_VIDC_VP9,
> +		.pixfmt_name = "VP9",
> +	},
> +};
> +
> +static struct color_format_info color_format_data_sm8550[] = {
> +	{
> +		.v4l2_color_format = V4L2_PIX_FMT_NV12,
> +		.vidc_color_format = MSM_VIDC_FMT_NV12,
> +		.pixfmt_name       = "NV12",
> +	},
> +	{
> +		.v4l2_color_format = V4L2_PIX_FMT_NV21,
> +		.vidc_color_format = MSM_VIDC_FMT_NV21,
> +		.pixfmt_name       = "NV21",
> +	},
> +	{
> +		.v4l2_color_format = V4L2_PIX_FMT_QC08C,
> +		.vidc_color_format = MSM_VIDC_FMT_NV12C,
> +		.pixfmt_name       = "NV12C",
> +	},
> +	{
> +		.v4l2_color_format = V4L2_PIX_FMT_QC10C,
> +		.vidc_color_format = MSM_VIDC_FMT_TP10C,
> +		.pixfmt_name       = "TP10C",
> +	},
> +	{
> +		.v4l2_color_format = V4L2_PIX_FMT_RGBA32,
> +		.vidc_color_format = MSM_VIDC_FMT_RGBA8888,
> +		.pixfmt_name       = "RGBA",
> +	},
> +};
> +
> +static struct color_primaries_info color_primaries_data_sm8550[] = {
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_DEFAULT,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_RESERVED,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_REC709,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT709,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_M,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_BG,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE170M,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT601_525,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE240M,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_ST240M,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_BT2020,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT2020,
> +	},
> +	{
> +		.v4l2_color_primaries  = V4L2_COLORSPACE_DCI_P3,
> +		.vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_RP431_2,
> +	},
> +};
> +
> +static struct transfer_char_info transfer_char_data_sm8550[] = {
> +	{
> +		.v4l2_transfer_char  = V4L2_XFER_FUNC_DEFAULT,
> +		.vidc_transfer_char  = MSM_VIDC_TRANSFER_RESERVED,
> +	},
> +	{
> +		.v4l2_transfer_char  = V4L2_XFER_FUNC_709,
> +		.vidc_transfer_char  = MSM_VIDC_TRANSFER_BT709,
> +	},
> +	{
> +		.v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE240M,
> +		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST240M,
> +	},
> +	{
> +		.v4l2_transfer_char  = V4L2_XFER_FUNC_SRGB,
> +		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SRGB_SYCC,
> +	},
> +	{
> +		.v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE2084,
> +		.vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ,
> +	},
> +};
> +
> +static struct matrix_coeff_info matrix_coeff_data_sm8550[] = {
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_DEFAULT,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_RESERVED,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_709,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV709,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV601,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_601,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_SMPTE240M,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT,
> +	},
> +	{
> +		.v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020_CONST_LUM,
> +		.vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT,
> +	},
> +};

Are you going to say that these tables are platform-specific instead of 
being generic to the driver?

> +
> +static struct msm_platform_core_capability core_data_sm8550[] = {
> +	/* {type, value} */
> +	{ENC_CODECS, H264 | HEVC},
> +	{DEC_CODECS, H264 | HEVC | VP9},
> +	{MAX_SESSION_COUNT, 16},
> +	{MAX_NUM_720P_SESSIONS, 16},
> +	{MAX_NUM_1080P_SESSIONS, 16},
> +	{MAX_NUM_4K_SESSIONS, 8},
> +	{MAX_NUM_8K_SESSIONS, 2},
> +	{MAX_RT_MBPF, 174080},	/* (8192x4352)/256 + (4096x2176)/256*/
> +	{MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */
> +	{MAX_MBPS, 7833600},	/* max_load
> +				 * 7680x4320@60fps or 3840x2176@240fps
> +				 * which is greater than 4096x2176@120fps,
> +				 * 8192x4320@48fps
> +				 */
> +	{MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */
> +	{MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */
> +	{MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */
> +	{MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */
> +	{MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */
> +	{MAX_ENH_LAYER_COUNT, 5},
> +	{NUM_VPP_PIPE, 4},
> +	{SW_PC, 1},
> +	{FW_UNLOAD, 0},
> +	{HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */
> +	{SW_PC_DELAY,         SW_PC_DELAY_VALUE        }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/
> +	{FW_UNLOAD_DELAY,     FW_UNLOAD_DELAY_VALUE    }, /* 3000 ms (>SW_PC_DELAY)*/
> +	{DCVS, 1},
> +	{DECODE_BATCH, 1},
> +	{DECODE_BATCH_TIMEOUT, 200},
> +	{STATS_TIMEOUT_MS, 2000},
> +	{NON_FATAL_FAULTS, 1},
> +	{DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING},

Unless there is a good reason, please change this to be a proper data 
structure instead of being a type-value array. With the T-V it is 
impossible to notice if the value is missing or duplicated. This comment 
also applies to the next 'capability' array.

> +};
> +
> +static struct msm_platform_inst_capability instance_cap_data_sm8550[] = {
> +	/* {cap, domain, codec,
> +	 *      min, max, step_or_mask, value,
> +	 *      v4l2_id,
> +	 *      hfi_id,
> +	 *      flags}
> +	 */
> +	{FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920},
> +
> +	{FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920},
> +
> +	{FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920},
> +
> +	{FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920},
> +
> +	{LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920},
> +
> +	{LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920},
> +
> +	{FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080},
> +
> +	{FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080},
> +
> +	{FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080},
> +
> +	{FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080},
> +
> +	{LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080},
> +
> +	{LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080},
> +
> +	{PIX_FMTS, ENC | DEC, H264,
> +		MSM_VIDC_FMT_NV12,
> +		MSM_VIDC_FMT_NV12C,
> +		MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C,
> +		MSM_VIDC_FMT_NV12C},
> +
> +	{PIX_FMTS, ENC | DEC, HEVC | VP9,
> +		MSM_VIDC_FMT_NV12,
> +		MSM_VIDC_FMT_TP10C,
> +		MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C |
> +		MSM_VIDC_FMT_TP10C,
> +		MSM_VIDC_FMT_NV12C},
> +
> +	{MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4,
> +		V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
> +		0,
> +		CAP_FLAG_VOLATILE},
> +
> +	{MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL,
> +		0, 64, 1, 4,
> +		V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
> +		HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE},
> +
> +	/* (8192 * 4320) / 256 */
> +	{MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240},
> +
> +	{MBPF, ENC, HEVC, 36, 138240, 1, 138240},
> +
> +	{MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240},
> +
> +	/* (4096 * 2304) / 256 */
> +	{MBPF, DEC, VP9, 36, 36864, 1, 36864},
> +
> +	/* (4096 * 2304) / 256 */
> +	{LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864},
> +
> +	/* Batch Mode Decode */
> +	/* TODO: update with new values based on updated voltage corner */
> +	{BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816},
> +
> +	/* (4096 * 2304) / 256 */
> +	{BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120},
> +
> +	{FRAME_RATE, ENC | DEC, CODECS_ALL,
> +		(MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
> +		1, (DEFAULT_FPS << 16),
> +		0,
> +		HFI_PROP_FRAME_RATE,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{OPERATING_RATE, ENC | DEC, CODECS_ALL,
> +		(MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
> +		1, (DEFAULT_FPS << 16)},
> +
> +	{INPUT_RATE, ENC | DEC, CODECS_ALL,
> +		(MINIMUM_FPS << 16), INT_MAX,
> +		1, (DEFAULT_FPS << 16)},
> +
> +	{TIMESTAMP_RATE, ENC | DEC, CODECS_ALL,
> +		(MINIMUM_FPS << 16), INT_MAX,
> +		1, (DEFAULT_FPS << 16)},
> +
> +	{SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8},
> +
> +	{MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25},
> +
> +	{MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25},
> +
> +	{MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60},
> +
> +	{MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675},
> +
> +	{MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200},
> +
> +	{MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320},
> +
> +	{MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200},
> +
> +	{MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583},
> +
> +	{MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405},
> +
> +	{MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234},
> +
> +	{HFLIP, ENC, CODECS_ALL,
> +		0, 1, 1, 0,
> +		V4L2_CID_HFLIP,
> +		HFI_PROP_FLIP,
> +		CAP_FLAG_OUTPUT_PORT |
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{VFLIP, ENC, CODECS_ALL,
> +		0, 1, 1, 0,
> +		V4L2_CID_VFLIP,
> +		HFI_PROP_FLIP,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +		CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{ROTATION, ENC, CODECS_ALL,
> +		0, 270, 90, 0,
> +		V4L2_CID_ROTATE,
> +		HFI_PROP_ROTATION,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{HEADER_MODE, ENC, CODECS_ALL,
> +		V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
> +		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
> +		BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
> +		BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
> +		V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
> +		V4L2_CID_MPEG_VIDEO_HEADER_MODE,
> +		HFI_PROP_SEQ_HEADER_MODE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR},
> +
> +	{WITHOUT_STARTCODE, ENC, CODECS_ALL,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
> +		HFI_PROP_NAL_LENGTH_FIELD,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{NAL_LENGTH_FIELD, ENC, CODECS_ALL,
> +		V4L2_MPEG_VIDEO_HEVC_SIZE_0,
> +		V4L2_MPEG_VIDEO_HEVC_SIZE_4,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4),
> +		V4L2_MPEG_VIDEO_HEVC_SIZE_0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
> +		HFI_PROP_NAL_LENGTH_FIELD,
> +		CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT},
> +
> +	/* TODO: Firmware introduced enumeration type for this
> +	 * with and without seq header.
> +	 */
> +	{REQUEST_I_FRAME, ENC, H264 | HEVC,
> +		0, 0, 0, 0,
> +		V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
> +		HFI_PROP_REQUEST_SYNC_FRAME,
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	/* Enc: Keeping CABAC and CAVLC as same bitrate.
> +	 * Dec: there's no use of Bitrate cap
> +	 */
> +	{BIT_RATE, ENC, H264 | HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_BITRATE,
> +		HFI_PROP_TOTAL_BITRATE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +		CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{BITRATE_MODE, ENC, H264,
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
> +		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
> +		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> +		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
> +		HFI_PROP_RATE_CONTROL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{BITRATE_MODE, ENC, HEVC,
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_CQ,
> +		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
> +		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
> +		BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ),
> +		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> +		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
> +		HFI_PROP_RATE_CONTROL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0,
> +		160000000, 1, 160000000},
> +
> +	{CAVLC_MAX_BITRATE, ENC, H264, 0,
> +		220000000, 1, 220000000},
> +
> +	{ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0,
> +		245000000, 1, 245000000},
> +
> +	{NUM_COMV, DEC, CODECS_ALL,
> +		0, INT_MAX, 1, 0},
> +
> +	{LOSSLESS, ENC, HEVC,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU},
> +
> +	{FRAME_SKIP_MODE, ENC, H264 | HEVC,
> +		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
> +		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
> +		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
> +		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) |
> +		BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
> +		V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
> +		V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{FRAME_RC_ENABLE, ENC, H264 | HEVC,
> +		0, 1, 1, 1,
> +		V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE},
> +
> +	{CONSTANT_QUALITY, ENC, HEVC,
> +		1, MAX_CONSTANT_QUALITY, 1, 90,
> +		V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY,
> +		HFI_PROP_CONSTANT_QUALITY,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +		CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{GOP_SIZE, ENC, CODECS_ALL,
> +		0, INT_MAX, 1, 2 * DEFAULT_FPS - 1,
> +		V4L2_CID_MPEG_VIDEO_GOP_SIZE,
> +		HFI_PROP_MAX_GOP_FRAMES,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +		CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{GOP_CLOSURE, ENC, H264 | HEVC,
> +		0, 1, 1, 1,
> +		V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
> +		0},
> +
> +	{B_FRAME, ENC, H264 | HEVC,
> +		0, 7, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_B_FRAMES,
> +		HFI_PROP_MAX_B_FRAMES,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{LTR_COUNT, ENC, H264 | HEVC,
> +		0, MAX_LTR_FRAME_COUNT_2, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_LTR_COUNT,
> +		HFI_PROP_LTR_COUNT,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{USE_LTR, ENC, H264 | HEVC,
> +		0,
> +		((1 << MAX_LTR_FRAME_COUNT_2) - 1),
> +		0, 0,
> +		V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES,
> +		HFI_PROP_LTR_USE,
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{MARK_LTR, ENC, H264 | HEVC,
> +		INVALID_DEFAULT_MARK_OR_USE_LTR,
> +		(MAX_LTR_FRAME_COUNT_2 - 1),
> +		1, INVALID_DEFAULT_MARK_OR_USE_LTR,
> +		V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX,
> +		HFI_PROP_LTR_MARK,
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{BASELAYER_PRIORITY, ENC, H264,
> +		0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID,
> +		HFI_PROP_BASELAYER_PRIORITYID,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{IR_TYPE, ENC, H264 | HEVC,
> +		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
> +		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
> +		BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) |
> +		BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC),
> +		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
> +		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{IR_PERIOD, ENC, H264 | HEVC,
> +		0, INT_MAX, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
> +		0,
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT |
> +		CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{AU_DELIMITER, ENC, H264 | HEVC,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
> +		HFI_PROP_AUD,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{MIN_QUALITY, ENC, H264 | HEVC,
> +		0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY,
> +		0,
> +		HFI_PROP_MAINTAIN_MIN_QUALITY,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{VBV_DELAY, ENC, H264 | HEVC,
> +		200, 300, 100, 300,
> +		V4L2_CID_MPEG_VIDEO_VBV_DELAY,
> +		HFI_PROP_VBV_DELAY,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{PEAK_BITRATE, ENC, H264 | HEVC,
> +		/* default peak bitrate is 10% larger than avg bitrate */
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
> +		HFI_PROP_TOTAL_PEAK_BITRATE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{MIN_FRAME_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> +		V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
> +		HFI_PROP_MIN_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{MIN_FRAME_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> +		V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
> +		HFI_PROP_MIN_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{I_FRAME_MIN_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> +		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP},
> +
> +	{I_FRAME_MIN_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> +		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP},
> +
> +	{P_FRAME_MIN_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> +		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP},
> +
> +	{P_FRAME_MIN_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> +		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP},
> +
> +	{B_FRAME_MIN_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> +		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP},
> +
> +	{B_FRAME_MIN_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> +		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP},
> +
> +	{MAX_FRAME_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
> +		HFI_PROP_MAX_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{MAX_FRAME_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
> +		HFI_PROP_MAX_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{I_FRAME_MAX_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP},
> +
> +	{I_FRAME_MAX_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP},
> +
> +	{P_FRAME_MAX_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP},
> +
> +	{P_FRAME_MAX_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP},
> +
> +	{B_FRAME_MAX_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP},
> +
> +	{B_FRAME_MAX_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP},
> +
> +	{I_FRAME_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{I_FRAME_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{P_FRAME_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{P_FRAME_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{B_FRAME_QP, ENC, HEVC,
> +		MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{B_FRAME_QP, ENC, H264,
> +		MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> +		V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
> +		HFI_PROP_QP_PACKED,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{LAYER_TYPE, ENC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
> +		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P),
> +		V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
> +		HFI_PROP_LAYER_ENCODING_TYPE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LAYER_TYPE, ENC, H264,
> +		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
> +		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
> +		BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) |
> +		BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P),
> +		V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
> +		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
> +		HFI_PROP_LAYER_ENCODING_TYPE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LAYER_ENABLE, ENC, H264,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
> +		HFI_PROP_LAYER_ENCODING_TYPE,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{LAYER_ENABLE, ENC, HEVC,
> +		0, 1, 1, 0,
> +		0,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{ENH_LAYER_COUNT, ENC, HEVC,
> +		0, 5, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
> +		HFI_PROP_LAYER_COUNT,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{ENH_LAYER_COUNT, ENC, H264,
> +		0, 5, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
> +		HFI_PROP_LAYER_COUNT,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L0_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
> +		HFI_PROP_BITRATE_LAYER1,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L0_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
> +		HFI_PROP_BITRATE_LAYER1,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L1_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
> +		HFI_PROP_BITRATE_LAYER2,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L1_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
> +		HFI_PROP_BITRATE_LAYER2,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L2_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
> +		HFI_PROP_BITRATE_LAYER3,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L2_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
> +		HFI_PROP_BITRATE_LAYER3,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L3_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
> +		HFI_PROP_BITRATE_LAYER4,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +	{L3_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
> +		HFI_PROP_BITRATE_LAYER4,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L4_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
> +		HFI_PROP_BITRATE_LAYER5,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L4_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
> +		HFI_PROP_BITRATE_LAYER5,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L5_BR, ENC, H264,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
> +		HFI_PROP_BITRATE_LAYER6,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{L5_BR, ENC, HEVC,
> +		1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> +		V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
> +		HFI_PROP_BITRATE_LAYER6,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> +			CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{ENTROPY_MODE, ENC, H264,
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> +		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
> +		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> +		V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
> +		HFI_PROP_CABAC_SESSION,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{ENTROPY_MODE, DEC, H264 | HEVC | VP9,
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> +		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
> +		BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
> +		V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> +		0,
> +		HFI_PROP_CABAC_SESSION},
> +
> +	{PROFILE, ENC | DEC, H264,
> +		V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
> +		V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
> +		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
> +		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) |
> +		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
> +		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
> +		BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH),
> +		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> +		V4L2_CID_MPEG_VIDEO_H264_PROFILE,
> +		HFI_PROP_PROFILE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{PROFILE, ENC | DEC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10),
> +		V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> +		HFI_PROP_PROFILE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{PROFILE, DEC, VP9,
> +		V4L2_MPEG_VIDEO_VP9_PROFILE_0,
> +		V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +		BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2),
> +		V4L2_MPEG_VIDEO_VP9_PROFILE_0,
> +		V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
> +		HFI_PROP_PROFILE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LEVEL, ENC, H264,
> +		V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
> +		V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0),
> +		V4L2_MPEG_VIDEO_H264_LEVEL_5_0,
> +		V4L2_CID_MPEG_VIDEO_H264_LEVEL,
> +		HFI_PROP_LEVEL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LEVEL, ENC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_5,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		HFI_PROP_LEVEL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LEVEL, DEC, H264,
> +		V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
> +		V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2),
> +		V4L2_MPEG_VIDEO_H264_LEVEL_6_1,
> +		V4L2_CID_MPEG_VIDEO_H264_LEVEL,
> +		HFI_PROP_LEVEL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LEVEL, DEC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
> +		V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		HFI_PROP_LEVEL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LEVEL, DEC, VP9,
> +		V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
> +		V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) |
> +		BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0),
> +		V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
> +		V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
> +		HFI_PROP_LEVEL,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{HEVC_TIER, ENC | DEC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
> +		V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH),
> +		V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
> +		V4L2_CID_MPEG_VIDEO_HEVC_TIER,
> +		HFI_PROP_TIER,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LF_MODE, ENC, H264,
> +		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
> +		DB_H264_DISABLE_SLICE_BOUNDARY,
> +		BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
> +		BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
> +		BIT(DB_H264_DISABLE_SLICE_BOUNDARY),
> +		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
> +		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
> +		HFI_PROP_DEBLOCKING_MODE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LF_MODE, ENC, HEVC,
> +		V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
> +		DB_HEVC_DISABLE_SLICE_BOUNDARY,
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) |
> +		BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) |
> +		BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY),
> +		V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
> +		HFI_PROP_DEBLOCKING_MODE,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{LF_ALPHA, ENC, H264,
> +		-6, 6, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA},
> +
> +	{LF_ALPHA, ENC, HEVC,
> +		-6, 6, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2},
> +
> +	{LF_BETA, ENC, H264,
> +		-6, 6, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA},
> +
> +	{LF_BETA, ENC, HEVC,
> +		-6, 6, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2},
> +
> +	{SLICE_MODE, ENC, H264 | HEVC,
> +		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
> +		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
> +		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
> +		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) |
> +		BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES),
> +		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
> +		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> +
> +	{SLICE_MAX_BYTES, ENC, H264 | HEVC,
> +		MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE,
> +		1, MIN_SLICE_BYTE_SIZE,
> +		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
> +		HFI_PROP_MULTI_SLICE_BYTES_COUNT,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{SLICE_MAX_MB, ENC, H264 | HEVC,
> +		1, MAX_SLICE_MB_SIZE, 1, 1,
> +		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
> +		HFI_PROP_MULTI_SLICE_MB_COUNT,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{MB_RC, ENC, H264 | HEVC,
> +		0, 1, 1, 1,
> +		V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{TRANSFORM_8X8, ENC, H264,
> +		0, 1, 1, 1,
> +		V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
> +		HFI_PROP_8X8_TRANSFORM,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
> +		MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET,
> +		1, MAX_CHROMA_QP_OFFSET,
> +		V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
> +		HFI_PROP_CHROMA_QP_OFFSET,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
> +		HFI_PROP_DECODE_ORDER_OUTPUT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
> +		0, 1, 1, 0,
> +		V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
> +		HFI_PROP_DECODE_ORDER_OUTPUT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
> +		0, 1, 1, 0,
> +		0,
> +		HFI_PROP_DECODE_ORDER_OUTPUT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> +		DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
> +		1, DEFAULT_MAX_HOST_BUF_COUNT,
> +		0,
> +		HFI_PROP_BUFFER_HOST_MAX_COUNT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> +		DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
> +		1, DEFAULT_MAX_HOST_BUF_COUNT,
> +		0,
> +		HFI_PROP_BUFFER_HOST_MAX_COUNT,
> +		CAP_FLAG_OUTPUT_PORT},
> +
> +	{CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1,
> +		DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
> +		V4L2_CID_MPEG_VIDEO_MUTE_YUV,
> +		HFI_PROP_CONCEAL_COLOR_8BIT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1,
> +		DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
> +		V4L2_CID_MPEG_VIDEO_MUTE_YUV,
> +		HFI_PROP_CONCEAL_COLOR_10BIT,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{STAGE, DEC | ENC, CODECS_ALL,
> +		MSM_VIDC_STAGE_1,
> +		MSM_VIDC_STAGE_2, 1,
> +		MSM_VIDC_STAGE_2,
> +		0,
> +		HFI_PROP_STAGE},
> +
> +	{PIPE, DEC | ENC, CODECS_ALL,
> +		MSM_VIDC_PIPE_1,
> +		MSM_VIDC_PIPE_4, 1,
> +		MSM_VIDC_PIPE_4,
> +		0,
> +		HFI_PROP_PIPE},
> +
> +	{POC, DEC, H264, 0, 2, 1, 1,
> +		0,
> +		HFI_PROP_PIC_ORDER_CNT_TYPE},
> +
> +	{QUALITY_MODE, ENC, CODECS_ALL,
> +		MSM_VIDC_MAX_QUALITY_MODE,
> +		MSM_VIDC_POWER_SAVE_MODE, 1,
> +		MSM_VIDC_POWER_SAVE_MODE},
> +
> +	{CODED_FRAMES, DEC, H264 | HEVC,
> +		CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE,
> +		1, CODED_FRAMES_PROGRESSIVE,
> +		0,
> +		HFI_PROP_CODED_FRAMES},
> +
> +	{BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8,
> +		0,
> +		HFI_PROP_LUMA_CHROMA_BIT_DEPTH},
> +
> +	{BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0,
> +		0},
> +
> +	{DEFAULT_HEADER, DEC, CODECS_ALL,
> +		0, 1, 1, 0,
> +		0,
> +		HFI_PROP_DEC_DEFAULT_HEADER},
> +
> +	{RAP_FRAME, DEC, CODECS_ALL,
> +		0, 1, 1, 1,
> +		0,
> +		HFI_PROP_DEC_START_FROM_RAP_FRAME,
> +		CAP_FLAG_INPUT_PORT},
> +
> +	{SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL,
> +		0, 1, 1, 1,
> +		0,
> +		HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME,
> +		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> +
> +	{ALL_INTRA, ENC, H264 | HEVC,
> +		0, 1, 1, 0,
> +		0,
> +		0,
> +		CAP_FLAG_OUTPUT_PORT},
> +};
> +
> +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_sm8550[] = {
> +	/* {cap, domain, codec,
> +	 *      children,
> +	 *      adjust, set}
> +	 */
> +
> +	{PIX_FMTS, ENC, H264,
> +		{IR_PERIOD}},
> +
> +	{PIX_FMTS, ENC, HEVC,
> +		{PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP,
> +			B_FRAME_QP, MIN_QUALITY, IR_PERIOD, LTR_COUNT}},
> +
> +	{PIX_FMTS, DEC, HEVC,
> +		{PROFILE}},
> +
> +	{FRAME_RATE, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_q16},
> +
> +	{HFLIP, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_flip},
> +
> +	{VFLIP, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_flip},
> +
> +	{ROTATION, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_rotation},
> +
> +	{HEADER_MODE, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_header_mode},
> +
> +	{WITHOUT_STARTCODE, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_nal_length},
> +
> +	{REQUEST_I_FRAME, ENC, H264 | HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_req_sync_frame},
> +
> +	{BIT_RATE, ENC, H264,
> +		{PEAK_BITRATE, L0_BR},
> +		msm_vidc_adjust_bitrate,
> +		msm_vidc_set_bitrate},
> +
> +	{BIT_RATE, ENC, HEVC,
> +		{PEAK_BITRATE, L0_BR},
> +		msm_vidc_adjust_bitrate,
> +		msm_vidc_set_bitrate},
> +
> +	{BITRATE_MODE, ENC, H264,
> +		{LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
> +			B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE,
> +			MIN_QUALITY, VBV_DELAY,
> +			PEAK_BITRATE, SLICE_MODE},
> +		msm_vidc_adjust_bitrate_mode,
> +		msm_vidc_set_u32_enum},
> +
> +	{BITRATE_MODE, ENC, HEVC,
> +		{LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
> +			B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT,
> +			BIT_RATE, MIN_QUALITY, VBV_DELAY,
> +			PEAK_BITRATE, SLICE_MODE},
> +		msm_vidc_adjust_bitrate_mode,
> +		msm_vidc_set_u32_enum},
> +
> +	{CONSTANT_QUALITY, ENC, HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_constant_quality},
> +
> +	{GOP_SIZE, ENC, CODECS_ALL,
> +		{ALL_INTRA},
> +		msm_vidc_adjust_gop_size,
> +		msm_vidc_set_gop_size},
> +
> +	{B_FRAME, ENC, H264 | HEVC,
> +		{ALL_INTRA},
> +		msm_vidc_adjust_b_frame,
> +		msm_vidc_set_u32},
> +
> +	{LTR_COUNT, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_ltr_count,
> +		msm_vidc_set_u32},
> +
> +	{USE_LTR, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_use_ltr,
> +		msm_vidc_set_use_and_mark_ltr},
> +
> +	{MARK_LTR, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_mark_ltr,
> +		msm_vidc_set_use_and_mark_ltr},
> +
> +	{IR_PERIOD, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_ir_period,
> +		msm_vidc_set_ir_period},
> +
> +	{AU_DELIMITER, ENC, H264 | HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32},
> +
> +	{MIN_QUALITY, ENC, H264,
> +		{0},
> +		msm_vidc_adjust_min_quality,
> +		msm_vidc_set_u32},
> +
> +	{MIN_QUALITY, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_min_quality,
> +		msm_vidc_set_u32},
> +
> +	{VBV_DELAY, ENC, H264 | HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_cbr_related_properties},
> +
> +	{PEAK_BITRATE, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_peak_bitrate,
> +		msm_vidc_set_cbr_related_properties},
> +
> +	{MIN_FRAME_QP, ENC, H264,
> +		{0},
> +		NULL,
> +		msm_vidc_set_min_qp},
> +
> +	{MIN_FRAME_QP, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_hevc_min_qp,
> +		msm_vidc_set_min_qp},
> +
> +	{MAX_FRAME_QP, ENC, H264,
> +		{0},
> +		NULL,
> +		msm_vidc_set_max_qp},
> +
> +	{MAX_FRAME_QP, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_hevc_max_qp,
> +		msm_vidc_set_max_qp},
> +
> +	{I_FRAME_QP, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_hevc_i_frame_qp,
> +		msm_vidc_set_frame_qp},
> +
> +	{I_FRAME_QP, ENC, H264,
> +		{0},
> +		NULL,
> +		msm_vidc_set_frame_qp},
> +
> +	{P_FRAME_QP, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_hevc_p_frame_qp,
> +		msm_vidc_set_frame_qp},
> +
> +	{P_FRAME_QP, ENC, H264,
> +		{0},
> +		NULL,
> +		msm_vidc_set_frame_qp},
> +
> +	{B_FRAME_QP, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_hevc_b_frame_qp,
> +		msm_vidc_set_frame_qp},
> +
> +	{B_FRAME_QP, ENC, H264,
> +		{0},
> +		NULL,
> +		msm_vidc_set_frame_qp},
> +
> +	{LAYER_TYPE, ENC, H264 | HEVC,
> +		{LTR_COUNT}},
> +
> +	{LAYER_ENABLE, ENC, H264 | HEVC,
> +		{0}},
> +
> +	{ENH_LAYER_COUNT, ENC, H264 | HEVC,
> +		{GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE,
> +			LTR_COUNT},
> +		msm_vidc_adjust_layer_count,
> +		msm_vidc_set_layer_count_and_type},
> +
> +	{L0_BR, ENC, H264 | HEVC,
> +		{L1_BR},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{L1_BR, ENC, H264 | HEVC,
> +		{L2_BR},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{L2_BR, ENC, H264 | HEVC,
> +		{L3_BR},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{L3_BR, ENC, H264 | HEVC,
> +		{L4_BR},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{L4_BR, ENC, H264 | HEVC,
> +		{L5_BR},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{L5_BR, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_layer_bitrate,
> +		msm_vidc_set_layer_bitrate},
> +
> +	{ENTROPY_MODE, ENC, H264,
> +		{BIT_RATE},
> +		msm_vidc_adjust_entropy_mode,
> +		msm_vidc_set_u32},
> +
> +	{PROFILE, ENC, H264,
> +		{ENTROPY_MODE, TRANSFORM_8X8},
> +		NULL,
> +		msm_vidc_set_u32_enum},
> +
> +	{PROFILE, DEC, H264,
> +		{ENTROPY_MODE},
> +		NULL,
> +		msm_vidc_set_u32_enum},
> +
> +	{PROFILE, ENC | DEC, HEVC,
> +		{0},
> +		msm_vidc_adjust_profile,
> +		msm_vidc_set_u32_enum},
> +
> +	{PROFILE, DEC, VP9,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32_enum},
> +
> +	{LEVEL, DEC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32_enum},
> +
> +	{LEVEL, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_level},
> +
> +	{HEVC_TIER, ENC | DEC, HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32_enum},
> +
> +	{LF_MODE, ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_deblock_mode},
> +
> +	{SLICE_MODE, ENC, H264 | HEVC,
> +		{STAGE},
> +		msm_vidc_adjust_slice_count,
> +		msm_vidc_set_slice_count},
> +
> +	{TRANSFORM_8X8, ENC, H264,
> +		{0},
> +		msm_vidc_adjust_transform_8x8,
> +		msm_vidc_set_u32},
> +
> +	{CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
> +		{0},
> +		msm_vidc_adjust_chroma_qp_index_offset,
> +		msm_vidc_set_chroma_qp_index_offset},
> +
> +	{DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
> +		{OUTPUT_ORDER},
> +		NULL,
> +		NULL},
> +
> +	{DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
> +		{OUTPUT_ORDER},
> +		NULL,
> +		NULL},
> +
> +	{OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
> +		{0},
> +		msm_vidc_adjust_output_order,
> +		msm_vidc_set_u32},
> +
> +	{INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> +		{0},
> +		msm_vidc_adjust_input_buf_host_max_count,
> +		msm_vidc_set_u32},
> +
> +	{INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_input_buf_host_max_count,
> +		msm_vidc_set_u32},
> +
> +	{OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> +		{0},
> +		msm_vidc_adjust_output_buf_host_max_count,
> +		msm_vidc_set_u32},
> +
> +	{OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
> +		{0},
> +		msm_vidc_adjust_output_buf_host_max_count,
> +		msm_vidc_set_u32},
> +
> +	{CONCEAL_COLOR_8BIT, DEC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32_packed},
> +
> +	{CONCEAL_COLOR_10BIT, DEC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32_packed},
> +
> +	{STAGE, ENC | DEC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_stage},
> +
> +	{STAGE, ENC, H264 | HEVC,
> +		{0},
> +		NULL,
> +		msm_vidc_set_stage},
> +
> +	{STAGE, DEC, H264 | HEVC | VP9,
> +		{0},
> +		NULL,
> +		msm_vidc_set_stage},
> +
> +	{PIPE, DEC | ENC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_pipe},
> +
> +	{RAP_FRAME, DEC, CODECS_ALL,
> +		{0},
> +		NULL,
> +		msm_vidc_set_u32},
> +
> +	{ALL_INTRA, ENC, H264 | HEVC,
> +		{LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE},
> +		msm_vidc_adjust_all_intra,
> +		NULL},
> +};
> +
> +/* Default UBWC config for LPDDR5 */
> +static struct msm_vidc_ubwc_config_data ubwc_config_sm8550[] = {
> +	UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1),
> +};
> +
> +static struct msm_vidc_format_capability format_data_sm8550 = {
> +	.codec_info = codec_data_sm8550,
> +	.codec_info_size = ARRAY_SIZE(codec_data_sm8550),
> +	.color_format_info = color_format_data_sm8550,
> +	.color_format_info_size = ARRAY_SIZE(color_format_data_sm8550),
> +	.color_prim_info = color_primaries_data_sm8550,
> +	.color_prim_info_size = ARRAY_SIZE(color_primaries_data_sm8550),
> +	.transfer_char_info = transfer_char_data_sm8550,
> +	.transfer_char_info_size = ARRAY_SIZE(transfer_char_data_sm8550),
> +	.matrix_coeff_info = matrix_coeff_data_sm8550,
> +	.matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_sm8550),
> +};
> +
> +/* name, min_kbps, max_kbps */
> +static const struct bw_table sm8550_bw_table[] = {
> +	{ "venus-cnoc",  1000, 1000     },
> +	{ "venus-ddr",   1000, 15000000 },

We have OPP tables for that. There is no need to limit the min/max, just 
put it to OPP.

> +};
> +
> +/* name */
> +static const struct pd_table sm8550_pd_table[] = {
> +	{ "iris-ctl" },
> +	{ "vcodec"   },
> +};
> +
> +/* name */
> +static const char * const sm8550_opp_table[] = { "mx", "mmcx", NULL };
> +
> +/* name, clock id, scaling */
> +static const struct clk_table sm8550_clk_table[] = {
> +	{ "gcc_video_axi0",         GCC_VIDEO_AXI0_CLK,     0 },
> +	{ "core_clk",               VIDEO_CC_MVS0C_CLK,     0 },
> +	{ "vcodec_clk",             VIDEO_CC_MVS0_CLK,      1 },
> +};

This strucuture looks like a perfect candidate to be replaced by 
devm_clk_bulk_get_all().

> +
> +/* name, exclusive_release */
> +static const struct clk_rst_table sm8550_clk_reset_table[] = {
> +	{ "video_axi_reset",        0  },

Can we assume that resets are generic at least?

> +};
> +
> +/* name, start, size, secure, dma_coherant, region, dma_mask */
> +const struct context_bank_table sm8550_context_bank_table[] = {
> +	{"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0xe0000000 - 1},
> +	{"qcom,vidc,cb-sec-non-pxl",   0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL,  0 },

Aren't these a properties of subdevices? If so, why are you putting them 
here?

> +};
> +
> +/* freq */
> +static struct freq_table sm8550_freq_table[] = {
> +	{533333333}, {444000000}, {366000000}, {338000000}, {240000000}

OPP table contents.

> +};
> +
> +/* register, value, mask */
> +static const struct reg_preset_table sm8550_reg_preset_table[] = {
> +	{ 0xB0088, 0x0, 0x11 },
> +};
> +
> +/* decoder properties */
> +static const u32 sm8550_vdec_psc_avc[] = {
> +	HFI_PROP_BITSTREAM_RESOLUTION,
> +	HFI_PROP_CROP_OFFSETS,
> +	HFI_PROP_CODED_FRAMES,
> +	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> +	HFI_PROP_PIC_ORDER_CNT_TYPE,
> +	HFI_PROP_PROFILE,
> +	HFI_PROP_LEVEL,
> +	HFI_PROP_SIGNAL_COLOR_INFO,
> +};
> +
> +static const u32 sm8550_vdec_psc_hevc[] = {
> +	HFI_PROP_BITSTREAM_RESOLUTION,
> +	HFI_PROP_CROP_OFFSETS,
> +	HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
> +	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> +	HFI_PROP_PROFILE,
> +	HFI_PROP_LEVEL,
> +	HFI_PROP_TIER,
> +	HFI_PROP_SIGNAL_COLOR_INFO,
> +};
> +
> +static const u32 sm8550_vdec_psc_vp9[] = {
> +	HFI_PROP_BITSTREAM_RESOLUTION,
> +	HFI_PROP_CROP_OFFSETS,
> +	HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
> +	HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> +	HFI_PROP_PROFILE,
> +	HFI_PROP_LEVEL,
> +};
> +
> +static const u32 sm8550_vdec_input_properties_avc[] = {
> +	HFI_PROP_NO_OUTPUT,
> +	HFI_PROP_SUBFRAME_INPUT,
> +};
> +
> +static const u32 sm8550_vdec_input_properties_hevc[] = {
> +	HFI_PROP_NO_OUTPUT,
> +	HFI_PROP_SUBFRAME_INPUT,
> +};
> +
> +static const u32 sm8550_vdec_input_properties_vp9[] = {
> +	HFI_PROP_NO_OUTPUT,
> +	HFI_PROP_SUBFRAME_INPUT,
> +};
> +
> +static const u32 sm8550_vdec_output_properties_avc[] = {
> +	HFI_PROP_WORST_COMPRESSION_RATIO,
> +	HFI_PROP_WORST_COMPLEXITY_FACTOR,
> +	HFI_PROP_PICTURE_TYPE,
> +	HFI_PROP_DPB_LIST,
> +	HFI_PROP_CABAC_SESSION,
> +};
> +
> +static const u32 sm8550_vdec_output_properties_hevc[] = {
> +	HFI_PROP_WORST_COMPRESSION_RATIO,
> +	HFI_PROP_WORST_COMPLEXITY_FACTOR,
> +	HFI_PROP_PICTURE_TYPE,
> +	HFI_PROP_DPB_LIST,
> +};
> +
> +static const u32 sm8550_vdec_output_properties_vp9[] = {
> +	HFI_PROP_WORST_COMPRESSION_RATIO,
> +	HFI_PROP_WORST_COMPLEXITY_FACTOR,
> +	HFI_PROP_PICTURE_TYPE,
> +	HFI_PROP_DPB_LIST,
> +};
> +
> +static const struct msm_vidc_platform_data sm8550_data = {
> +	/* resources dependent on other module */
> +	.bw_tbl = sm8550_bw_table,
> +	.bw_tbl_size = ARRAY_SIZE(sm8550_bw_table),
> +	.clk_tbl = sm8550_clk_table,
> +	.clk_tbl_size = ARRAY_SIZE(sm8550_clk_table),
> +	.clk_rst_tbl = sm8550_clk_reset_table,
> +	.clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table),
> +	.subcache_tbl = NULL,
> +	.subcache_tbl_size = 0,
> +
> +	/* populate context bank */
> +	.context_bank_tbl = sm8550_context_bank_table,
> +	.context_bank_tbl_size = ARRAY_SIZE(sm8550_context_bank_table),
> +
> +	/* populate power domain and opp table */
> +	.pd_tbl = sm8550_pd_table,
> +	.pd_tbl_size = ARRAY_SIZE(sm8550_pd_table),
> +	.opp_tbl = sm8550_opp_table,
> +	.opp_tbl_size = ARRAY_SIZE(sm8550_opp_table),
> +
> +	/* platform specific resources */
> +	.freq_tbl = sm8550_freq_table,
> +	.freq_tbl_size = ARRAY_SIZE(sm8550_freq_table),
> +	.reg_prst_tbl = sm8550_reg_preset_table,
> +	.reg_prst_tbl_size = ARRAY_SIZE(sm8550_reg_preset_table),
> +	.fwname = "vpu30_4v",
> +	.pas_id = 9,
> +
> +	/* caps related resorces */
> +	.core_data = core_data_sm8550,
> +	.core_data_size = ARRAY_SIZE(core_data_sm8550),
> +	.inst_cap_data = instance_cap_data_sm8550,
> +	.inst_cap_data_size = ARRAY_SIZE(instance_cap_data_sm8550),
> +	.inst_cap_dependency_data = instance_cap_dependency_data_sm8550,
> +	.inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_sm8550),
> +	.ubwc_config = ubwc_config_sm8550,
> +	.format_data = &format_data_sm8550,
> +
> +	/* decoder properties related*/
> +	.psc_avc_tbl = sm8550_vdec_psc_avc,
> +	.psc_avc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_avc),
> +	.psc_hevc_tbl = sm8550_vdec_psc_hevc,
> +	.psc_hevc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_hevc),
> +	.psc_vp9_tbl = sm8550_vdec_psc_vp9,
> +	.psc_vp9_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_vp9),
> +	.dec_input_prop_avc = sm8550_vdec_input_properties_avc,
> +	.dec_input_prop_hevc = sm8550_vdec_input_properties_hevc,
> +	.dec_input_prop_vp9 = sm8550_vdec_input_properties_vp9,
> +	.dec_input_prop_size_avc = ARRAY_SIZE(sm8550_vdec_input_properties_avc),
> +	.dec_input_prop_size_hevc = ARRAY_SIZE(sm8550_vdec_input_properties_hevc),
> +	.dec_input_prop_size_vp9 = ARRAY_SIZE(sm8550_vdec_input_properties_vp9),
> +	.dec_output_prop_avc = sm8550_vdec_output_properties_avc,
> +	.dec_output_prop_hevc = sm8550_vdec_output_properties_hevc,
> +	.dec_output_prop_vp9 = sm8550_vdec_output_properties_vp9,
> +	.dec_output_prop_size_avc = ARRAY_SIZE(sm8550_vdec_output_properties_avc),
> +	.dec_output_prop_size_hevc = ARRAY_SIZE(sm8550_vdec_output_properties_hevc),
> +	.dec_output_prop_size_vp9 = ARRAY_SIZE(sm8550_vdec_output_properties_vp9),

Size should come next to the array reference.

> +};
> +
> +static int msm_vidc_init_data(struct msm_vidc_core *core)
> +{
> +	d_vpr_h("%s: initialize sm8550 data\n", __func__);
> +
> +	core->platform->data = sm8550_data;
> +

Please use of_device_match_data() instead.

> +	return 0;
> +}
> +
> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core)
> +{
> +	return msm_vidc_init_data(core);
> +}

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations
  2023-07-28 13:23 ` [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations Vikash Garodia
@ 2023-07-28 14:19   ` Dmitry Baryshkov
  2023-08-14 20:00     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 14:19 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 16:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements iris3 specific buffer size calculation for
> firmware internal buffers, input and output buffers for
> encoder and decoder.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 ++++++++++++++++++++
>   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
>   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 ++++++++
>   3 files changed, 2095 insertions(+)
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
>   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
> 
> diff --git a/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> new file mode 100644
> index 0000000..cb068ca
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> @@ -0,0 +1,1481 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef __HFI_BUFFER_IRIS3__
> +#define __HFI_BUFFER_IRIS3__
> +
> +#include <linux/types.h>
> +
> +#include "hfi_property.h"
> +
> +typedef u8      HFI_U8;
> +typedef s8      HFI_S8;
> +typedef u16     HFI_U16;
> +typedef s16     HFI_S16;
> +typedef u32     HFI_U32;
> +typedef s32     HFI_S32;
> +typedef u64     HFI_U64;
> +typedef u32     HFI_BOOL;

No custom typedefs please.

> +
> +#ifndef MIN
> +#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
> +#endif
> +
> +#ifndef MAX
> +#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
> +#endif

You have seen <linux/minmax.h>, didn't you? If so, why are you adding 
new wrappers?

> +
> +#define HFI_ALIGNMENT_4096 (4096)
> +
> +#define BUF_SIZE_ALIGN_16 (16)
> +#define BUF_SIZE_ALIGN_32 (32)
> +#define BUF_SIZE_ALIGN_64 (64)
> +#define BUF_SIZE_ALIGN_128 (128)
> +#define BUF_SIZE_ALIGN_256 (256)
> +#define BUF_SIZE_ALIGN_512 (512)
> +#define BUF_SIZE_ALIGN_4096 (4096)

So nice, so useless.

> +
> +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \
> +	(b) * (b)) : (((a) + (b) - 1) & (~((b) - 1))))

Can you use ALIGN instead?

> +
> +#define HFI_WORKMODE_1 1
> +#define HFI_WORKMODE_2 2
> +
> +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64)
> +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16)
> +
> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8)
> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32)
> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8)
> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16)
> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4)
> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48)
> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4)
> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24)
> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4)
> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16)
> +
> +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = HFI_ALIGN(frame_width, stride_multiple))

macros with side actions are not really welcomed. Especially as they do 
not bring any additional value and can be inlined.

> +
> +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> +	min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \
> +	min_buf_height_multiple))
> +
> +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = HFI_ALIGN(frame_width, stride_multiple))
> +
> +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> +	min_buf_height_multiple) (buf_height = HFI_ALIGN((((frame_height) + 1) \
> +	 >> 1),	min_buf_height_multiple))
> +
> +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufsize, y_stride, y_buf_height, \
> +	uv_buf_size, uv_stride, uv_buf_height) \
> +	do { \
> +		y_bufsize = (y_stride * y_buf_height); \
> +		uv_buf_size = (uv_stride * uv_buf_height); \
> +		buf_size = HFI_ALIGN(y_bufsize + uv_buf_size, HFI_ALIGNMENT_4096) \
> +	} while (0)
> +
> +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufsize, y_stride, y_buf_height) \
> +	(y_bufsize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
> +
> +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \
> +	uv_stride, uv_buf_height) \
> +	(uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096))
> +
> +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\
> +	frame_width, frame_height, y_stride_multiple,\
> +	y_buffer_height_multiple, uv_stride_multiple, \
> +	uv_buffer_height_multiple, y_metadata_stride_multiple, \
> +	y_metadata_buffer_height_multiple, \
> +	uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \
> +	do { \
> +		HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size;   \
> +		HFI_U32 stride, _height; \
> +		HFI_U32 half_height = (frame_height + 1) >> 1; \
> +		HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\
> +					y_stride_multiple); \
> +		HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\
> +					y_buffer_height_multiple); \
> +		HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\
> +		HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \
> +					uv_stride_multiple); \
> +		HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \
> +					uv_buffer_height_multiple); \
> +		HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\
> +		HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\
> +				y_metadata_stride_multiple, \
> +			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\
> +		HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \
> +				y_metadata_buffer_height_multiple,\
> +			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\
> +		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \
> +				_height);    \
> +		HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\
> +				uv_metadata_stride_multiple, \
> +			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \
> +		HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\
> +				uv_metadata_buffer_height_multiple,\
> +			HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\
> +		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \
> +				 _height); \
> +		buf_size = (y_buf_size + uv_buf_size + y_meta_size + \
> +			uv_meta_size) << 1;\
> +	} while (0)

Even more macro with side effects. Please consider rewriting them to be 
functions. Small function is usually easier to understand compared to 
the complex macro.

> +
> +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
> +	do { \
> +		stride = HFI_ALIGN(frame_width, 192); \
> +		stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
> +	} while (0)
> +
> +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> +				min_buf_height_multiple) \
> +	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> +
> +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
> +	do { \
> +		stride = HFI_ALIGN(frame_width, 192); \
> +		stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
> +	} while (0)
> +
> +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> +				min_buf_height_multiple) \
> +	(buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
> +			min_buf_height_multiple))
> +
> +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\
> +		y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \
> +	do {	\
> +		y_buf_size = (y_stride * y_buf_height); \
> +		uv_buf_size = (uv_stride * uv_buf_height); \
> +		buf_size = y_buf_size + uv_buf_size \
> +	} while (0)
> +
> +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \
> +					y_buf_height) \
> +	(y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
> +
> +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \
> +					uv_buf_height) \
> +	(uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096))
> +
> +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride, y_buf_height, \
> +	uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \
> +	uv_md_height)\
> +	do { \
> +		HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \
> +		HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\
> +						y_buf_height); \
> +		HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \
> +						uv_buf_height); \
> +		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \
> +						y_md_height); \
> +		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \
> +						uv_md_height); \
> +		buf_size = y_data_size + uv_data_size + y_md_size + \
> +						uv_md_size; \
> +	} while (0)
> +
> +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = HFI_ALIGN(frame_width * 2, stride_multiple))
> +
> +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> +				min_buf_height_multiple) \
> +	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> +
> +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = HFI_ALIGN(frame_width * 2, stride_multiple))
> +
> +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> +				min_buf_height_multiple) \
> +	(buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
> +			min_buf_height_multiple))
> +
> +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \
> +	y_buf_height, uv_data_size, uv_stride, uv_buf_height) \
> +	do { \
> +		y_data_size = HFI_ALIGN(y_stride * y_buf_height, \
> +				HFI_ALIGNMENT_4096);\
> +		uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \
> +				HFI_ALIGNMENT_4096); \
> +		buf_size = y_data_size + uv_data_size; \
> +	} while (0)
> +
> +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = ((frame_width * 3) + stride_multiple - 1) & \
> +			 (0xffffffff - (stride_multiple - 1)))
> +
> +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \
> +			min_buf_height_multiple) \
> +	(buf_height = ((frame_height + min_buf_height_multiple - 1) & \
> +			(0xffffffff - (min_buf_height_multiple - 1))))
> +
> +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
> +	(buf_size = ((stride) * (buf_height)))
> +
> +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \
> +	(stride = HFI_ALIGN((frame_width << 2), stride_multiple))
> +
> +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \
> +			min_buf_height_multiple) \
> +	(buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> +
> +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
> +	(buf_size = (stride) * (buf_height))
> +
> +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \
> +				buf_height) \
> +	(buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096))
> +
> +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \
> +	metadata_buffer_size, stride, buf_height, _metadata_tride, \
> +	_metadata_buf_height) \
> +	do { \
> +		HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \
> +				stride, buf_height); \
> +		HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \
> +				_metadata_tride, _metadata_buf_height); \
> +		buf_size = data_buf_size + metadata_buffer_size \
> +	} while (0)
> +
> +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\
> +	metadata_stride_multiple, tile_width_in_pels) \
> +	((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels - 1)) /\
> +	tile_width_in_pels), metadata_stride_multiple)))
> +
> +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height, \
> +	metadata_height_multiple, tile_height_in_pels) \
> +	((metadata_buf_height = HFI_ALIGN(((frame_height + \
> +	(tile_height_in_pels - 1)) / tile_height_in_pels), \
> +	metadata_height_multiple)))
> +
> +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \
> +	metadata_stride_multiple, tile_width_in_pels) \
> +	((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\
> +	(tile_width_in_pels - 1)) / tile_width_in_pels), \
> +	metadata_stride_multiple)))
> +
> +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height,\
> +	metadata_height_multiple, tile_height_in_pels) \
> +	(metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \
> +	(tile_height_in_pels - 1)) / tile_height_in_pels), \
> +	metadata_height_multiple))
> +
> +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \
> +					_metadata_buf_height) \
> +	((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \
> +					HFI_ALIGNMENT_4096)))
> +
> +#define BUFFER_ALIGNMENT_512_BYTES 512
> +#define BUFFER_ALIGNMENT_256_BYTES 256
> +#define BUFFER_ALIGNMENT_128_BYTES 128
> +#define BUFFER_ALIGNMENT_64_BYTES 64
> +#define BUFFER_ALIGNMENT_32_BYTES 32
> +#define BUFFER_ALIGNMENT_16_BYTES 16
> +#define BUFFER_ALIGNMENT_8_BYTES 8
> +#define BUFFER_ALIGNMENT_4_BYTES 4

-ETOOMUCH.

[skipped the rest, internal reviewer exception]

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
                   ` (34 preceding siblings ...)
  2023-07-28 14:01 ` Dmitry Baryshkov
@ 2023-07-28 14:34 ` Bryan O'Donoghue
  35 siblings, 0 replies; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-07-28 14:34 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 14:23, Vikash Garodia wrote:
> This patch series introduces support for Qualcomm new video acceleration
> hardware architecture, used for video stream decoding/encoding. This driver
> is based on new communication protocol between video hardware and application
> processor.

I think my main comment and question for this driver is; what 
specifically about the sm8550 requires an entirely new driver for the 
venus block ?

We have a re-implementation of the HFI as an example.

What are the specifics of the technical barriers, if any, that preclude 
adding or extending the existing venus codebase to enable the new silicon ?

---
bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 33/33] iris: enable building of iris video driver
  2023-07-28 13:23 ` [PATCH 33/33] iris: enable building of iris video driver Vikash Garodia
@ 2023-07-28 14:40   ` Dmitry Baryshkov
  2023-07-28 15:25   ` Bryan O'Donoghue
  1 sibling, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 14:40 UTC (permalink / raw)
  To: Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm,
	quic_dikshita

On Fri, 28 Jul 2023 at 17:28, Vikash Garodia <quic_vgarodia@quicinc.com> wrote:
>
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>
> This adds iris driver Makefile and Kconfig, also changes
> v4l2 platform/qcom Makefile/Kconfig in order to
> enable compilation of the driver.
>
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  drivers/media/platform/qcom/Kconfig       |  1 +
>  drivers/media/platform/qcom/Makefile      |  1 +
>  drivers/media/platform/qcom/iris/Kconfig  | 15 ++++++++++
>  drivers/media/platform/qcom/iris/Makefile | 46 +++++++++++++++++++++++++++++++
>  4 files changed, 63 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/Kconfig
>  create mode 100644 drivers/media/platform/qcom/iris/Makefile
>
> diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
> index cc5799b..b86bebd 100644
> --- a/drivers/media/platform/qcom/Kconfig
> +++ b/drivers/media/platform/qcom/Kconfig
> @@ -4,3 +4,4 @@ comment "Qualcomm media platform drivers"
>
>  source "drivers/media/platform/qcom/camss/Kconfig"
>  source "drivers/media/platform/qcom/venus/Kconfig"
> +source "drivers/media/platform/qcom/iris/Kconfig"
> diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
> index 4f055c3..83eea29 100644
> --- a/drivers/media/platform/qcom/Makefile
> +++ b/drivers/media/platform/qcom/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  obj-y += camss/
>  obj-y += venus/
> +obj-y += iris/
> diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig
> new file mode 100644
> index 0000000..d434c31
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/Kconfig
> @@ -0,0 +1,15 @@
> +config VIDEO_QCOM_IRIS
> +       tristate "Qualcomm Iris V4L2 encoder/decoder driver"
> +       depends on V4L_MEM2MEM_DRIVERS
> +       depends on VIDEO_DEV && QCOM_SMEM
> +       depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> +       select QCOM_MDT_LOADER if ARCH_QCOM
> +       select QCOM_SCM
> +       select VIDEOBUF2_DMA_CONTIG
> +       select V4L2_MEM2MEM_DEV
> +       select DMABUF_HEAPS
> +       help
> +         This is a V4L2 driver for Qualcomm Iris video accelerator
> +         hardware. It accelerates encoding and decoding operations
> +         on various Qualcomm SoCs.
> +         To compile this driver as a module choose m here.
> diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
> new file mode 100644
> index 0000000..e681c4f
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/Makefile
> @@ -0,0 +1,46 @@
> +KBUILD_OPTIONS+= VIDEO_ROOT=$(KERNEL_SRC)/$(M)
> +
> +VIDEO_COMPILE_TIME = $(shell date)
> +VIDEO_COMPILE_BY = $(shell whoami | sed 's/\\/\\\\/')
> +VIDEO_COMPILE_HOST = $(shell uname -n)
> +VIDEO_GEN_PATH = $(srctree)/$(src)/vidc/inc/video_generated_h
> +
> +$(shell echo '#define VIDEO_COMPILE_TIME "$(VIDEO_COMPILE_TIME)"' > $(VIDEO_GEN_PATH))
> +$(shell echo '#define VIDEO_COMPILE_BY "$(VIDEO_COMPILE_BY)"' >> $(VIDEO_GEN_PATH))
> +$(shell echo '#define VIDEO_COMPILE_HOST "$(VIDEO_COMPILE_HOST)"' >> $(VIDEO_GEN_PATH))

Why do you need this at all?

> +
> +iris-objs += vidc/src/msm_vidc_v4l2.o \
> +                  vidc/src/msm_vidc_vb2.o \
> +                  vidc/src/msm_vidc.o \
> +                  vidc/src/msm_vdec.o \
> +                  vidc/src/msm_venc.o \
> +                  vidc/src/msm_vidc_driver.o \
> +                  vidc/src/msm_vidc_control.o \
> +                  vidc/src/msm_vidc_buffer.o \
> +                  vidc/src/msm_vidc_power.o \
> +                  vidc/src/msm_vidc_probe.o \
> +                  vidc/src/resources.o \
> +                  vidc/src/firmware.o \
> +                  vidc/src/msm_vidc_debug.o \
> +                  vidc/src/msm_vidc_memory.o \
> +                  vidc/src/venus_hfi.o \
> +                  vidc/src/venus_hfi_queue.o \
> +                  vidc/src/hfi_packet.o \
> +                  vidc/src/venus_hfi_response.o \
> +                  vidc/src/msm_vidc_state.o \
> +                  platform/common/src/msm_vidc_platform.o \
> +                  platform/sm8550/src/msm_vidc_sm8550.o \
> +                  variant/common/src/msm_vidc_variant.o \
> +                  variant/iris3/src/msm_vidc_buffer_iris3.o \
> +                  variant/iris3/src/msm_vidc_iris3.o \
> +                  variant/iris3/src/msm_vidc_power_iris3.o \
> +                  variant/iris3/src/msm_vidc_bus_iris3.o \
> +                  variant/iris3/src/msm_vidc_clock_iris3.o
> +
> +obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o
> +
> +ccflags-y += -I$(srctree)/$(src)/vidc/inc
> +ccflags-y += -I$(srctree)/$(src)/platform/common/inc
> +ccflags-y += -I$(srctree)/$(src)/platform/sm8550/inc
> +ccflags-y += -I$(srctree)/$(src)/variant/common/inc
> +ccflags-y += -I$(srctree)/$(src)/variant/iris3/inc

For me this is a sign of the bad structure of the include files.
Please define proper interfaces between submodules. The parts of the
driver usually should include files from the top-level dir only (and
from the local subdirectory of course).

> --
> 2.7.4
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 33/33] iris: enable building of iris video driver
  2023-07-28 13:23 ` [PATCH 33/33] iris: enable building of iris video driver Vikash Garodia
  2023-07-28 14:40   ` Dmitry Baryshkov
@ 2023-07-28 15:25   ` Bryan O'Donoghue
  2023-07-28 15:51     ` Dmitry Baryshkov
  1 sibling, 1 reply; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-07-28 15:25 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 14:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This adds iris driver Makefile and Kconfig, also changes
> v4l2 platform/qcom Makefile/Kconfig in order to
> enable compilation of the driver.

This is not a meaningfully bisectable patch.

It should go with the addition of the driver. Its good practice to break 
up incremental changes to a driver in a series but, I don't see why you 
really need to do that when adding a whole new driver.

Just

- Documentation
- Bindings
- Driver code

On the other hand if you were switching on IRIS in the default defconfig 
then that should be a separate patch.

If we were say adding inter-frame power-collapse to the existing venus 
as part of a series, then that makes sense as a standalone patch but IMO 
when adding a whole new driver, add it as one.

Its easier to read that way

---
bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 06/33] iris: vidc: define video core and instance context
  2023-07-28 13:23 ` [PATCH 06/33] iris: vidc: define video core and instance context Vikash Garodia
@ 2023-07-28 15:47   ` Bryan O'Donoghue
  2023-08-14 19:04     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-07-28 15:47 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 14:23, Vikash Garodia wrote:
> +#define call_iris_op(d, op, ...)			\
> +	(((d) && (d)->iris_ops && (d)->iris_ops->op) ? \
> +	((d)->iris_ops->op(__VA_ARGS__)) : 0)
> +
> +struct msm_vidc_iris_ops {
> +	int (*boot_firmware)(struct msm_vidc_core *core);
> +	int (*raise_interrupt)(struct msm_vidc_core *core);
> +	int (*clear_interrupt)(struct msm_vidc_core *core);
> +	int (*prepare_pc)(struct msm_vidc_core *core);
> +	int (*power_on)(struct msm_vidc_core *core);
> +	int (*power_off)(struct msm_vidc_core *core);
> +	int (*watchdog)(struct msm_vidc_core *core, u32 intr_status);
> +};

So I don't see how this code supports booting the venus firmware, is 
that not required on 8550 ?

I've applied the full patchset to -next

We don't appear to have enumerated callbacks for booting, clearing 
interrupts..

grep -r clear_interrupt drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
call_iris_op(core, clear_interrupt, core);

grep -r boot_firmware drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
call_iris_op(core, boot_firmware, core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
call_iris_op(core, boot_firmware, core);

There is dead code @ raise_interrupt..

grep -r raise_interrupt drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:	 
call_iris_op(core, raise_interrupt, core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:		 
//call_iris_op(core, raise_interrupt, core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:		 
//call_iris_op(core, raise_interrupt, core);

grep -r clear_interrupt drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
call_iris_op(core, clear_interrupt, core);

grep -r prepare_pc drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:int 
__prepare_pc(struct msm_vidc_core *core)
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
call_iris_op(core, prepare_pc, core);


Here we have an admixture of the new name "Iris" with the old name "venus"

grep -r power_on drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:static int 
__venus_power_on(struct msm_vidc_core *core)
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
call_iris_op(core, power_on, core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
__venus_power_on(core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:		goto 
err_venus_power_on;
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:err_venus_power_on:
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
__venus_power_on(core);

grep -r power_off drivers/media/platform/qcom/iris/vidc/src/*
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:		goto skip_power_off;
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:skip_power_off:
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:static int 
__venus_power_off(struct msm_vidc_core *core)
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:	rc = 
call_iris_op(core, power_off, core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
__venus_power_off(core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
__venus_power_off(core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
__venus_power_off(core);
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: 
__venus_power_off(core);

Lending credence to the argument we could incorporate all of some of the 
is logic in the existing venus driver.

---
bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 33/33] iris: enable building of iris video driver
  2023-07-28 15:25   ` Bryan O'Donoghue
@ 2023-07-28 15:51     ` Dmitry Baryshkov
  0 siblings, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-07-28 15:51 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vikash Garodia, stanimir.k.varbanov,
	agross, andersson, konrad.dybcio, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 18:25, Bryan O'Donoghue wrote:
> On 28/07/2023 14:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This adds iris driver Makefile and Kconfig, also changes
>> v4l2 platform/qcom Makefile/Kconfig in order to
>> enable compilation of the driver.
> 
> This is not a meaningfully bisectable patch.
> 
> It should go with the addition of the driver. Its good practice to break 
> up incremental changes to a driver in a series but, I don't see why you 
> really need to do that when adding a whole new driver.
> 
> Just
> 
> - Documentation
> - Bindings
> - Driver code
> 
> On the other hand if you were switching on IRIS in the default defconfig 
> then that should be a separate patch.
> 
> If we were say adding inter-frame power-collapse to the existing venus 
> as part of a series, then that makes sense as a standalone patch but IMO 
> when adding a whole new driver, add it as one.
> 
> Its easier to read that way

It wouldn't pass through mailing list filters.

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI)
  2023-07-28 13:23 ` [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI) Vikash Garodia
@ 2023-07-28 15:58   ` Bryan O'Donoghue
  2023-08-14 19:11     ` Dikshita Agarwal
  2023-07-31  9:02   ` Bryan O'Donoghue
  1 sibling, 1 reply; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-07-28 15:58 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 14:23, Vikash Garodia wrote:
> +	rc = hfi_packet_sys_intraframe_powercollapse(core, core->packet,
> +						     core->packet_size, enable);
> +	if (rc)
> +		return rc;

I'm 99.9999999999 % sure this is misnamed.

"Inter" means in-between two things.
"Intra" means inside of one thing.

So "intraframe" means inside of one frame "interframe" would mean power 
collapsing in-between two frames, which is what I think this does.

And I'd still rather be adding inter-frame power-collapse to as many 
different versions of the existing silicon and new silicon as opposed to 
segregating it off in a new driver.

I'm assuming that more than sm8550 supports it since @ the end of the 
day this is a firmware feature to power-collapse during an active 
session when we aren't busy.

---
bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
  2023-07-28 13:34   ` Dmitry Baryshkov
@ 2023-07-28 16:23   ` Bjorn Andersson
  2023-07-28 17:50   ` Nicolas Dufresne
  2023-07-31 21:23   ` Krzysztof Kozlowski
  3 siblings, 0 replies; 108+ messages in thread
From: Bjorn Andersson @ 2023-07-28 16:23 UTC (permalink / raw)
  To: Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm,
	quic_dikshita

On Fri, Jul 28, 2023 at 06:53:14PM +0530, Vikash Garodia wrote:
> Here is the implementation of v4l2 wrapper functions for all
> v4l2 IOCTLs.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>

In patch 2 you got this right, where the first Signed-off-by is that of
the author (defined by a From:), in the rest you should up as the
author, but Dikshita was the first one certifying the origin of this
code.

I suspect you need a Co-developed-by: Dikshita throughout the series?


Your subject should include the subsystem prefix (media: ), it's not
clear from the presented description if the "vidc" string adds value -
are there other functionality under iris?

For all the patches, do read:
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes


> ---
>  .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>  .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>  2 files changed, 1030 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> new file mode 100644
> index 0000000..3766c9d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_V4L2_H_
> +#define _MSM_VIDC_V4L2_H_
> +
> +#include <linux/fs.h>
> +#include <linux/poll.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-ioctl.h>
> +
> +int msm_v4l2_open(struct file *filp);

We already have a v4l2 driver for msm platforms.

If it is concluded that there needs to be two (as was asked by others),
then this isn't "the one and only MSM video codec/controller/c???
driver". This would be the qcom_iris_ driver, or something along those
lines. All functions, variables, defines etc should be named
accordingly.

Regards,
Bjorn

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-07-28 13:23 ` [PATCH 11/33] iris: vidc: add helpers for memory management Vikash Garodia
@ 2023-07-28 16:28   ` Bjorn Andersson
  2023-07-28 17:22     ` Konrad Dybcio
  2023-08-14 19:05     ` Dikshita Agarwal
  0 siblings, 2 replies; 108+ messages in thread
From: Bjorn Andersson @ 2023-07-28 16:28 UTC (permalink / raw)
  To: Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm,
	quic_dikshita

On Fri, Jul 28, 2023 at 06:53:22PM +0530, Vikash Garodia wrote:
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
[..]
> +static const struct msm_vidc_memory_ops msm_mem_ops = {
> +	.dma_buf_get                    = msm_vidc_dma_buf_get,
> +	.dma_buf_put                    = msm_vidc_dma_buf_put,
> +	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
> +	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
> +	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
> +	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
> +	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
> +	.memory_alloc_map               = msm_vidc_memory_alloc_map,
> +	.memory_unmap_free              = msm_vidc_memory_unmap_free,
> +	.buffer_region                  = msm_vidc_buffer_region,

Will there ever be more than one implementation of the
msm_vidc_memory_ops?

Unless there's a really strong reason, just call the functions directly
without the function pointers and call_mem_op(), this will be slightly
faster, but more importantly it allows for much faster navigation of the
code base.

Regards,
Bjorn

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 08/33] iris: vidc: add video decoder files
  2023-07-28 13:23 ` [PATCH 08/33] iris: vidc: add video decoder files Vikash Garodia
@ 2023-07-28 17:21   ` Konrad Dybcio
  2023-08-14 19:13     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:21 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> This implements decoder functionalities of the driver.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
I see a whole bunch of shifts, ANDs, etc.

Please convert that to GENMASK + FIELD_PREP/FIELD_GET

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-07-28 16:28   ` Bjorn Andersson
@ 2023-07-28 17:22     ` Konrad Dybcio
  2023-08-14 19:06       ` Dikshita Agarwal
  2023-08-14 19:05     ` Dikshita Agarwal
  1 sibling, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:22 UTC (permalink / raw)
  To: Bjorn Andersson, Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm, quic_dikshita

On 28.07.2023 18:28, Bjorn Andersson wrote:
> On Fri, Jul 28, 2023 at 06:53:22PM +0530, Vikash Garodia wrote:
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
> [..]
>> +static const struct msm_vidc_memory_ops msm_mem_ops = {
>> +	.dma_buf_get                    = msm_vidc_dma_buf_get,
>> +	.dma_buf_put                    = msm_vidc_dma_buf_put,
>> +	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
>> +	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
>> +	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
>> +	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
>> +	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
>> +	.memory_alloc_map               = msm_vidc_memory_alloc_map,
>> +	.memory_unmap_free              = msm_vidc_memory_unmap_free,
>> +	.buffer_region                  = msm_vidc_buffer_region,
> 
> Will there ever be more than one implementation of the
> msm_vidc_memory_ops?
> 
> Unless there's a really strong reason, just call the functions directly
> without the function pointers and call_mem_op(), this will be slightly
> faster, but more importantly it allows for much faster navigation of the
> code base.
Same for HFI ops

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 12/33] iris: vidc: add helper functions for resource management
  2023-07-28 13:23 ` [PATCH 12/33] iris: vidc: add helper functions for resource management Vikash Garodia
@ 2023-07-28 17:30   ` Konrad Dybcio
  2023-08-14 19:07     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:30 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements ops to initialize, enable and disable extrenal
> resources needed by video driver like power domains, clocks etc.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
There's a whole bunch of kerneldoc abuses (comments should start with
/* and not /**). Make sure you have proper spaces between single-line
C-style comments (e.g. /*Get should be /* Get etc.)

Capitalizing the first word within the comment would be nice too.


Do we need a separate bus table? i.e. does it make sense to adjust the
bandwidth values separately from the clock rates?

Do you think there will be more than one set of msm_vidc_resources_ops?
Perhaps it'd make sense to drop that layer of abstraction if not. Many
function names could drop the __ prefix.

A whole bunch of d_vpr_h seem almost excessive.

MSM_VIDC_CLKFLAG_* are unused.

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-07-28 13:32 ` [PATCH 00/33] Qualcomm video decoder/encoder driver Dmitry Baryshkov
@ 2023-07-28 17:38   ` Nicolas Dufresne
  0 siblings, 0 replies; 108+ messages in thread
From: Nicolas Dufresne @ 2023-07-28 17:38 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm
  Cc: quic_dikshita

Hi Dmitry,

Le vendredi 28 juillet 2023 à 16:32 +0300, Dmitry Baryshkov a écrit :
> On 28/07/2023 16:23, Vikash Garodia wrote:
> > This patch series introduces support for Qualcomm new video acceleration
> > hardware architecture, used for video stream decoding/encoding. This driver
> > is based on new communication protocol between video hardware and application
> > processor.
> > 
> > This driver comes with below capabilities:
> > - V4L2 complaint video driver with M2M and STREAMING capability.
> > - Supports H264, H265, VP9 decoders.
> > - Supports H264, H265 encoders.
> > 
> > This driver comes with below features:
> > - Centralized resource and memory management.
> > - Centralized management of core and instance states.
> > - Defines platform specific capabilities and features. As a results, it provides
> >    a single point of control to enable/disable a given feature depending on
> >    specific platform capabilities.
> > - Handles hardware interdependent configurations. For a given configuration from
> >    client, the driver checks for hardware dependent configuration/s and updates
> >    the same.
> > - Handles multiple complex video scenarios involving state transitions - DRC,
> >    Drain, Seek, back to back DRC, DRC during Drain sequence, DRC during Seek
> >    sequence.
> > - Introduces a flexible way for driver to subscribe for any property with
> >    hardware. Hardware would inform driver with those subscribed property with any
> >    change in value.
> > - Introduces performance (clock and bus) model based on new hardware
> >    architecture.
> > - Introduces multi thread safe design to handle communication between client and
> >    hardware.
> > - Adapts encoder quality improvements available in new hardware architecture.
> > - Implements asynchronous communication with hardware to achieve better
> >    experience in low latency usecases.
> > - Supports multi stage hardware architecture for encode/decode.
> > - Output and capture planes are controlled independently. Thereby providing a
> >    way to reconfigure individual plane.
> > - Hardware packetization layer supports synchronization between configuration
> >    packet and data packet.
> > - Introduces a flexibility to receive a hardware response for a given command
> >    packet.
> > - Native hardware support of LAST flag which is mandatory to align with port
> >    reconfiguration and DRAIN sequence as per V4L guidelines.
> > - Native hardware support for drain sequence.
> > 
> > I think that the driver is in good shape for mainline kernel, and I hope the
> > review comments will help to improve it, so please do review, and make comments.
> 
> No bindings, no driver. Please post start the series from the bindings.

In your next iteration, make sure to include full v4l2-compliance report in your
cover letter since we cannot assume maintainers.

In addition to this, we now ask for fluster scores for each of your supported
decoders. We expect the results to have no timeout, and ideally the
error/failure explained (aka unsupported resolution, profile, subsampling, bit
depth, etc.). Note that inter-resolution change is not possible with V4L2 today,
so no need to explain why these VP9 tests fails. Fluster supports V4L2 decoding
through GStreamer (gst-launch + video4linux plugin) and FFMPEG at the moment. It
will run through ITU conformance vectors for HEVC and H.264, and run through
libvpx and and chromium test vectors for VP9.

https://github.com/fluendo/fluster

regards,
Nicolas

> 
> > 
> > Dikshita Agarwal (17):
> >    iris: vidc: add core functions
> >    iris: add vidc wrapper file
> >    iris: vidc: add vb2 ops
> >    iris: vidc: add helpers for memory management
> >    iris: vidc: add helper functions for resource management
> >    iris: vidc: add helper functions for power management
> >    iris: add helpers for media format
> >    iris: vidc: add PIL functionality for video firmware
> >    iris: platform: add platform files
> >    iris: platform: sm8550: add capability file for sm8550
> >    iris: variant: add helper functions for register handling
> >    iris: variant: iris3: add iris3 specific ops
> >    iris: variant: iris3: add helpers for buffer size calculations
> >    iris: variant: iris3: add helper for bus and clock calculation
> >    iris: variant: iris: implement the logic to compute bus bandwidth
> >    iris: variant: iris3: implement logic to compute clock frequency
> >    iris: enable building of iris video driver
> > 
> > Vikash Garodia (16):
> >    MAINTAINERS: Add Qualcomm Iris video accelerator driver
> >    iris: vidc: add v4l2 wrapper file
> >    iris: vidc: define video core and instance context
> >    iris: iris: add video encoder files
> >    iris: vidc: add video decoder files
> >    iris: vidc: add control files
> >    iris: vidc: add helper functions
> >    iris: vidc: add helpers for state management
> >    iris: add vidc buffer files
> >    iris: vidc: define various structures and enum
> >    iris: vidc: hfi: add Host Firmware Interface (HFI)
> >    iris: vidc: hfi: add Host Firmware Interface (HFI) response handling
> >    iris: vidc: hfi: add helpers for handling shared queues
> >    iris: vidc: hfi: Add packetization layer
> >    iris: vidc: hfi: defines HFI properties and enums
> >    iris: vidc: add debug files
> > 
> >   MAINTAINERS                                        |   10 +
> >   drivers/media/platform/qcom/Kconfig                |    1 +
> >   drivers/media/platform/qcom/Makefile               |    1 +
> >   drivers/media/platform/qcom/iris/Kconfig           |   15 +
> >   drivers/media/platform/qcom/iris/Makefile          |   46 +
> >   .../iris/platform/common/inc/msm_vidc_platform.h   |  305 ++
> >   .../iris/platform/common/src/msm_vidc_platform.c   | 2499 ++++++++++++
> >   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
> >   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727 ++++++++
> >   .../iris/variant/common/inc/msm_vidc_variant.h     |   22 +
> >   .../iris/variant/common/src/msm_vidc_variant.c     |  163 +
> >   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481 +++++++
> >   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
> >   .../qcom/iris/variant/iris3/inc/msm_vidc_iris3.h   |   15 +
> >   .../iris/variant/iris3/inc/msm_vidc_power_iris3.h  |   17 +
> >   .../iris/variant/iris3/inc/perf_static_model.h     |  229 ++
> >   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 +++
> >   .../iris/variant/iris3/src/msm_vidc_bus_iris3.c    |  884 ++++
> >   .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  |  627 +++
> >   .../qcom/iris/variant/iris3/src/msm_vidc_iris3.c   |  954 +++++
> >   .../iris/variant/iris3/src/msm_vidc_power_iris3.c  |  345 ++
> >   .../media/platform/qcom/iris/vidc/inc/firmware.h   |   18 +
> >   .../platform/qcom/iris/vidc/inc/hfi_command.h      |  190 +
> >   .../media/platform/qcom/iris/vidc/inc/hfi_packet.h |   52 +
> >   .../platform/qcom/iris/vidc/inc/hfi_property.h     |  666 +++
> >   .../platform/qcom/iris/vidc/inc/msm_media_info.h   |  599 +++
> >   .../media/platform/qcom/iris/vidc/inc/msm_vdec.h   |   40 +
> >   .../media/platform/qcom/iris/vidc/inc/msm_venc.h   |   34 +
> >   .../media/platform/qcom/iris/vidc/inc/msm_vidc.h   |   60 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_buffer.h  |   32 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_control.h |   26 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_core.h    |  165 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   |  186 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_driver.h  |  352 ++
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_inst.h    |  207 +
> >   .../qcom/iris/vidc/inc/msm_vidc_internal.h         |  787 ++++
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_memory.h  |   83 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_power.h   |   94 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_state.h   |  102 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |   77 +
> >   .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |   39 +
> >   .../media/platform/qcom/iris/vidc/inc/resources.h  |  259 ++
> >   .../media/platform/qcom/iris/vidc/inc/venus_hfi.h  |   66 +
> >   .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |   89 +
> >   .../qcom/iris/vidc/inc/venus_hfi_response.h        |   26 +
> >   .../media/platform/qcom/iris/vidc/src/firmware.c   |  294 ++
> >   .../media/platform/qcom/iris/vidc/src/hfi_packet.c |  657 +++
> >   .../media/platform/qcom/iris/vidc/src/msm_vdec.c   | 2091 ++++++++++
> >   .../media/platform/qcom/iris/vidc/src/msm_venc.c   | 1484 +++++++
> >   .../media/platform/qcom/iris/vidc/src/msm_vidc.c   |  841 ++++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_buffer.c  |  290 ++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_control.c |  824 ++++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   |  581 +++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_driver.c  | 4276 ++++++++++++++++++++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_memory.c  |  448 ++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_power.c   |  560 +++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   |  660 +++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_state.c   | 1607 ++++++++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    |  953 +++++
> >   .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     |  605 +++
> >   .../media/platform/qcom/iris/vidc/src/resources.c  | 1321 ++++++
> >   .../media/platform/qcom/iris/vidc/src/venus_hfi.c  | 1503 +++++++
> >   .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  |  537 +++
> >   .../qcom/iris/vidc/src/venus_hfi_response.c        | 1607 ++++++++
> >   64 files changed, 35357 insertions(+)
> >   create mode 100644 drivers/media/platform/qcom/iris/Kconfig
> >   create mode 100644 drivers/media/platform/qcom/iris/Makefile
> >   create mode 100644 drivers/media/platform/qcom/iris/platform/common/inc/msm_vidc_platform.h
> >   create mode 100644 drivers/media/platform/qcom/iris/platform/common/src/msm_vidc_platform.c
> >   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> >   create mode 100644 drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_iris3.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_power_iris3.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/inc/perf_static_model.h
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_bus_iris3.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_iris3.c
> >   create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_power_iris3.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/firmware.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_command.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_packet.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/hfi_property.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_media_info.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vdec.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_venc.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_buffer.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_control.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_core.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_driver.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_inst.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_internal.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_memory.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_power.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_state.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/resources.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_response.h
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/firmware.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/hfi_packet.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vdec.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_venc.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_buffer.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_control.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_driver.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_power.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_state.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/resources.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
> >   create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_response.c
> > 
> 


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 10/33] iris: vidc: add helper functions
  2023-07-28 13:23 ` [PATCH 10/33] iris: vidc: add helper functions Vikash Garodia
@ 2023-07-28 17:41   ` Konrad Dybcio
  2023-08-14 19:15     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:41 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> This implements common helper functions for v4l2 to vidc and
> vice versa conversion for different enums.
> Add helpers for state checks, buffer management, locks etc.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
[...]

> +
> +#define is_odd(val) ((val) % 2 == 1)
> +#define in_range(val, min, max) (((min) <= (val)) && ((val) <= (max)))
> +#define COUNT_BITS(a, out) {       \
hweight.* functions?

[...]

> +
> +const char *cap_name(enum msm_vidc_inst_capability_type cap_id)
> +{
> +	const char *name = "UNKNOWN CAP";
Perhaps it'd be worth to include the unknown cap id here

> +
> +	if (cap_id >= ARRAY_SIZE(cap_name_arr))
> +		goto exit;
> +
> +	name = cap_name_arr[cap_id];
> +
> +exit:
> +	return name;
> +}
[...]

> +
> +const char *buf_name(enum msm_vidc_buffer_type type)
> +{
> +	const char *name = "UNKNOWN BUF";
Similarly here

> +
> +	if (type >= ARRAY_SIZE(buf_type_name_arr))
> +		goto exit;
> +
> +	name = buf_type_name_arr[type];
> +
> +exit:
> +	return name;
> +}
[...]

> +const char *v4l2_type_name(u32 port)
> +{
> +	switch (port) {
switch-case seems a bit excessive here.

> +	case INPUT_MPLANE:      return "INPUT";
> +	case OUTPUT_MPLANE:     return "OUTPUT";
> +	}
> +
> +	return "UNKNOWN";
> +}
[...]

There's some more stuff I'd comment on, but 4500 lines in a single patch
is way too much to logically follow.

Couple more style suggestions:
- use Reverse-Christmas-tree sorting for variable declarations
- some oneliner functions could possibly become preprocessor macros
- when printing giant debug messages, you may want to use loops
- make sure your indentation is in order, 100 chars per line is
  totally fine
- generally inline magic hex values are discouraged, but if they're
  necessary, the hex should be lowercase

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 13/33] iris: vidc: add helper functions for power management
  2023-07-28 13:23 ` [PATCH 13/33] iris: vidc: add helper functions for power management Vikash Garodia
@ 2023-07-28 17:46   ` Konrad Dybcio
  2023-08-14 19:10     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:46 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> this implements functions for calculating current load of the
> hardware. Depending on the count of instances and
> resolutions it selects the best clock rate for the video
> core. Also it scales clocks, power and enable/disable dcvs.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---[...]

> +
> +/* TODO: Move to dtsi OR use source clock instead of branch clock.*/
> +#define MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO 3
Seems unused in this patch.

> +
> +enum vidc_bus_type {
> +	PERF,
> +	DDR,
> +	LLCC,
> +};
> +
> +/*
> + * Minimum dimensions for which to calculate bandwidth.
> + * This means that anything bandwidth(0, 0) ==
> + * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
> + */
> +static const struct {
> +	int height, width;
> +} BASELINE_DIMENSIONS = {
> +	.width = 1280,
> +	.height = 720,
> +};
> +
> +/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
if 'b', the multiplier must be 1024 or it makes no sense

> +#define kbps(__mbps) ((__mbps) * 1000)
> +#define bps(__mbps) (kbps(__mbps) * 1000)
> +
[...]

> +void __dump(struct dump dump[], int len)
> +{
> +	int c = 0;
> +
> +	for (c = 0; c < len; ++c) {
> +		char format_line[128] = "", formatted_line[128] = "";
That's a lot of bytes on the stack..

> +
> +		if (dump[c].val == DUMP_HEADER_MAGIC) {
> +			snprintf(formatted_line, sizeof(formatted_line), "%s\n",
> +				 dump[c].key);
> +		} else {
> +			snprintf(format_line, sizeof(format_line),
> +				 "    %-35s: %s\n", dump[c].key,
> +					 dump[c].format);
> +			snprintf(formatted_line, sizeof(formatted_line),
> +				 format_line, dump[c].val);
> +		}
> +		d_vpr_b("%s", formatted_line);
> +	}
> +}
> +
> +u64 msm_vidc_max_freq(struct msm_vidc_inst *inst)
> +{
> +	struct msm_vidc_core *core;
> +	struct frequency_table *freq_tbl;
> +	u64 freq = 0;
> +
> +	core = inst->core;
> +
> +	if (!core->resource || !core->resource->freq_set.freq_tbl ||
> +	    !core->resource->freq_set.count) {
> +		i_vpr_e(inst, "%s: invalid frequency table\n", __func__);
> +		return freq;
> +	}
> +	freq_tbl = core->resource->freq_set.freq_tbl;
Do we need a separate freuqency table if we have OPP?
[...]


> +	if (inst->power.fw_cf) {
> +		cf = inst->power.fw_cf;
> +		frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2;
too magic!

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
  2023-07-28 13:34   ` Dmitry Baryshkov
  2023-07-28 16:23   ` Bjorn Andersson
@ 2023-07-28 17:50   ` Nicolas Dufresne
  2023-08-14 19:14     ` Dikshita Agarwal
  2023-07-31 21:23   ` Krzysztof Kozlowski
  3 siblings, 1 reply; 108+ messages in thread
From: Nicolas Dufresne @ 2023-07-28 17:50 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

Le vendredi 28 juillet 2023 à 18:53 +0530, Vikash Garodia a écrit :
> Here is the implementation of v4l2 wrapper functions for all
> v4l2 IOCTLs.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>  .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>  2 files changed, 1030 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> new file mode 100644
> index 0000000..3766c9d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_V4L2_H_
> +#define _MSM_VIDC_V4L2_H_
> +
> +#include <linux/fs.h>
> +#include <linux/poll.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-ioctl.h>
> +
> +int msm_v4l2_open(struct file *filp);
> +int msm_v4l2_close(struct file *filp);
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap);
> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
> +		      struct v4l2_fmtdesc *f);
> +int msm_v4l2_try_fmt(struct file *file, void *fh,
> +		     struct v4l2_format *f);
> +int msm_v4l2_s_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_g_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_s_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_g_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_s_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_g_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_reqbufs(struct file *file, void *fh,
> +		     struct v4l2_requestbuffers *b);
> +int msm_v4l2_querybuf(struct file *file, void *fh,
> +		      struct v4l2_buffer *b);
> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
> +			 struct v4l2_create_buffers *b);
> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
> +			 struct v4l2_buffer *b);
> +int msm_v4l2_qbuf(struct file *file, void *fh,
> +		  struct v4l2_buffer *b);
> +int msm_v4l2_dqbuf(struct file *file, void *fh,
> +		   struct v4l2_buffer *b);
> +int msm_v4l2_streamon(struct file *file, void *fh,
> +		      enum v4l2_buf_type i);
> +int msm_v4l2_streamoff(struct file *file, void *fh,
> +		       enum v4l2_buf_type i);
> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
> +			     const struct v4l2_event_subscription *sub);
> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
> +			       const struct v4l2_event_subscription *sub);
> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_decoder_cmd *enc);
> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_decoder_cmd *dec);
> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
> +			     struct v4l2_frmsizeenum *fsize);
> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
> +				 struct v4l2_frmivalenum *fival);
> +int msm_v4l2_queryctrl(struct file *file, void *fh,
> +		       struct v4l2_queryctrl *ctrl);
> +int msm_v4l2_querymenu(struct file *file, void *fh,
> +		       struct v4l2_querymenu *qmenu);
> +unsigned int msm_v4l2_poll(struct file *filp,
> +			   struct poll_table_struct *pt);
> +void msm_v4l2_m2m_device_run(void *priv);
> +void msm_v4l2_m2m_job_abort(void *priv);
> +
> +#endif // _MSM_VIDC_V4L2_H_
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> new file mode 100644
> index 0000000..6dfb18b
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> @@ -0,0 +1,953 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "msm_vidc.h"
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_inst.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_v4l2.h"
> +
> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
> +{
> +	if (!filp || !filp->private_data)
> +		return NULL;
> +	return container_of(filp->private_data,
> +					struct msm_vidc_inst, fh);
> +}
> +
> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
> +{
> +	int poll = 0;
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return POLLERR;
> +	}
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		poll = POLLERR;
> +		goto exit;
> +	}
> +
> +	poll = msm_vidc_poll((void *)inst, filp, pt);
> +	if (poll)
> +		goto exit;
> +
> +exit:
> +	put_inst(inst);
> +	return poll;
> +}
> +
> +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 *inst;
> +
> +	inst = msm_vidc_open(core, vid_dev->type);
> +	if (!inst) {
> +		d_vpr_e("Failed to create instance, type = %d\n",
> +			vid_dev->type);
> +		return -ENOMEM;
> +	}
> +	filp->private_data = &inst->fh;
> +	return 0;
> +}
> +
> +int msm_v4l2_close(struct file *filp)
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +
> +	inst = get_vidc_inst(filp, NULL);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_close(inst);
> +	filp->private_data = NULL;
> +	return rc;
> +}
> +
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !cap) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);

You always takes both locks, which may indicate that you have one too many lock.
Any reason my the m2m_ctx->q_lock did not work for you ?

> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_querycap((void *)inst, cap);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_fmt(struct file *filp, void *fh,
> +		      struct v4l2_fmtdesc *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_fmt((void *)inst, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_fmt(struct file *filp, void *fh,
> +		   struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_fmt(struct file *filp, void *fh,
> +		   struct v4l2_format *f)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !f) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_fmt((void *)inst, f);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_selection(struct file *filp, void *fh,
> +			 struct v4l2_selection *s)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !s) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_s_selection((void *)inst, s);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_selection(struct file *filp, void *fh,
> +			 struct v4l2_selection *s)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !s) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_selection((void *)inst, s);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_s_parm(struct file *filp, void *fh,
> +		    struct v4l2_streamparm *a)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !a) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_s_param((void *)inst, a);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_g_parm(struct file *filp, void *fh,
> +		    struct v4l2_streamparm *a)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !a) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_g_param((void *)inst, a);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_reqbufs(struct file *filp, void *fh,
> +		     struct v4l2_requestbuffers *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_querybuf(struct file *filp, void *fh,
> +		      struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_querybuf((void *)inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
> +			 struct v4l2_create_buffers *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_create_bufs((void *)inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
> +			 struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	struct video_device *vdev = video_devdata(filp);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_qbuf(struct file *filp, void *fh,
> +		  struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	struct video_device *vdev = video_devdata(filp);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
> +	if (rc)
> +		goto exit;
> +
> +exit:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_dqbuf(struct file *filp, void *fh,
> +		   struct v4l2_buffer *b)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !b) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_dqbuf(inst, b);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_streamon(struct file *filp, void *fh,
> +		      enum v4l2_buf_type i)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto exit;
> +	}
> +
> +	rc = msm_vidc_streamon((void *)inst, i);
> +	if (rc)
> +		goto exit;
> +
> +exit:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_streamoff(struct file *filp, void *fh,
> +		       enum v4l2_buf_type i)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_streamoff((void *)inst, i);
> +	if (rc)
> +		i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
> +
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
> +			     const struct v4l2_event_subscription *sub)
> +{
> +	struct msm_vidc_inst *inst;
> +	int rc = 0;
> +
> +	inst = container_of(fh, struct msm_vidc_inst, fh);
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !sub) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_subscribe_event((void *)inst, sub);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
> +			       const struct v4l2_event_subscription *sub)
> +{
> +	struct msm_vidc_inst *inst;
> +	int rc = 0;
> +
> +	inst = container_of(fh, struct msm_vidc_inst, fh);
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !sub) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	rc = msm_vidc_unsubscribe_event((void *)inst, sub);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh,
> +			     struct v4l2_decoder_cmd *dec)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !dec) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
> +			 struct v4l2_decoder_cmd *dec)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	enum msm_vidc_event event;
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	if (!dec) {
> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	if (dec->cmd != V4L2_DEC_CMD_START &&
> +	    dec->cmd != V4L2_DEC_CMD_STOP) {
> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
> +	rc = inst->event_handle(inst, event, NULL);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh,
> +			     struct v4l2_encoder_cmd *enc)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !enc) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
> +			 struct v4l2_encoder_cmd *enc)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	enum msm_vidc_event event;
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	if (!enc) {
> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	if (enc->cmd != V4L2_ENC_CMD_START &&
> +	    enc->cmd != V4L2_ENC_CMD_STOP) {
> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
> +		rc = -EINVAL;
> +		goto unlock;
> +	}
> +	event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
> +	rc = inst->event_handle(inst, event, NULL);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_framesizes(struct file *filp, void *fh,
> +			     struct v4l2_frmsizeenum *fsize)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !fsize) {
> +		d_vpr_e("%s: invalid params: %pK %pK\n",
> +			__func__, inst, fsize);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_framesizes((void *)inst, fsize);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_enum_frameintervals(struct file *filp, void *fh,
> +				 struct v4l2_frmivalenum *fival)
> +
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !fival) {
> +		d_vpr_e("%s: invalid params: %pK %pK\n",
> +			__func__, inst, fival);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_enum_frameintervals((void *)inst, fival);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_queryctrl(struct file *filp, void *fh,
> +		       struct v4l2_queryctrl *ctrl)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !ctrl) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_query_ctrl((void *)inst, ctrl);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +int msm_v4l2_querymenu(struct file *filp, void *fh,
> +		       struct v4l2_querymenu *qmenu)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !qmenu) {
> +		d_vpr_e("%s: invalid params %pK %pK\n",
> +			__func__, inst, qmenu);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);
> +	inst_lock(inst, __func__);
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> +		rc = -EBUSY;
> +		goto unlock;
> +	}
> +	rc = msm_vidc_query_menu((void *)inst, qmenu);
> +	if (rc)
> +		goto unlock;
> +
> +unlock:
> +	inst_unlock(inst, __func__);
> +	client_unlock(inst, __func__);
> +	put_inst(inst);
> +
> +	return rc;
> +}
> +
> +void msm_v4l2_m2m_device_run(void *priv)
> +{
> +	d_vpr_l("%s(): device_run\n", __func__);
> +}
> +
> +void msm_v4l2_m2m_job_abort(void *priv)
> +{
> +	struct msm_vidc_inst *inst = priv;
> +
> +	if (!inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +	i_vpr_h(inst, "%s: m2m job aborted\n", __func__);
> +	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
> +}


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 14/33] iris: vidc: add helpers for state management
  2023-07-28 13:23 ` [PATCH 14/33] iris: vidc: add helpers for state management Vikash Garodia
@ 2023-07-28 17:52   ` Konrad Dybcio
  2023-08-14 19:17     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:52 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> This implements the functions to handle different core
> and instance state transitions.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
[...]

> +enum msm_vidc_core_sub_state {
> +	CORE_SUBSTATE_NONE                   = 0x0,
> +	CORE_SUBSTATE_POWER_ENABLE           = BIT(0),
> +	CORE_SUBSTATE_GDSC_HANDOFF           = BIT(1),
> +	CORE_SUBSTATE_PM_SUSPEND             = BIT(2),
> +	CORE_SUBSTATE_FW_PWR_CTRL            = BIT(3),
> +	CORE_SUBSTATE_PAGE_FAULT             = BIT(4),
> +	CORE_SUBSTATE_CPU_WATCHDOG           = BIT(5),
> +	CORE_SUBSTATE_VIDEO_UNRESPONSIVE     = BIT(6),
> +	CORE_SUBSTATE_MAX                    = BIT(7),
Why store it in an enum if they're not consecutive? You can make them
preprocessor #defines.

> +};
> +
> +enum msm_vidc_core_event_type {
> +	CORE_EVENT_NONE                      = BIT(0),
> +	CORE_EVENT_UPDATE_SUB_STATE          = BIT(1),
> +};
Ditto (even though techinically they're consecutive)

> +
> +enum msm_vidc_state {
> +	MSM_VIDC_OPEN,
> +	MSM_VIDC_INPUT_STREAMING,
> +	MSM_VIDC_OUTPUT_STREAMING,
> +	MSM_VIDC_STREAMING,
> +	MSM_VIDC_CLOSE,
> +	MSM_VIDC_ERROR,
> +};
> +
> +#define MSM_VIDC_SUB_STATE_NONE          0
> +#define MSM_VIDC_MAX_SUB_STATES          6
> +/*
> + * max value of inst->sub_state if all
> + * the 6 valid bits are set i.e 111111==>63
> + */
> +#define MSM_VIDC_MAX_SUB_STATE_VALUE     ((1 << MSM_VIDC_MAX_SUB_STATES) - 1)
> +
> +enum msm_vidc_sub_state {
> +	MSM_VIDC_DRAIN                     = BIT(0),
> +	MSM_VIDC_DRC                       = BIT(1),
> +	MSM_VIDC_DRAIN_LAST_BUFFER         = BIT(2),
> +	MSM_VIDC_DRC_LAST_BUFFER           = BIT(3),
> +	MSM_VIDC_INPUT_PAUSE               = BIT(4),
> +	MSM_VIDC_OUTPUT_PAUSE              = BIT(5),
Ditto

[...]

> +static int msm_vidc_core_init_wait_state(struct msm_vidc_core *core,
> +					 enum msm_vidc_core_event_type type,
> +					 struct msm_vidc_event_data *data)
> +{
> +	int rc = 0;
rc seems never assigned again, good to drop

[...]

> +
> +static int msm_vidc_core_init_state(struct msm_vidc_core *core,
> +				    enum msm_vidc_core_event_type type,
> +				    struct msm_vidc_event_data *data)
> +{
> +	int rc = 0;
Ditto

[...]

> +static int msm_vidc_core_error_state(struct msm_vidc_core *core,
> +				     enum msm_vidc_core_event_type type,
> +				     struct msm_vidc_event_data *data)
> +{
> +	int rc = 0;
Ditto

[...]

> +int msm_vidc_update_core_state(struct msm_vidc_core *core,
> +			       enum msm_vidc_core_state request_state, const char *func)
> +{
> +	struct msm_vidc_core_state_handle *state_handle = NULL;
> +	int rc = 0;
Ditto

[...]

> +int msm_vidc_change_core_state(struct msm_vidc_core *core,
> +			       enum msm_vidc_core_state request_state, const char *func)
> +{
> +	enum msm_vidc_allow allow;
> +	int rc = 0;
Ditto

[...]

> +bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state)
> +{
> +	return inst->state == state;
> +}
> +
> +bool is_sub_state(struct msm_vidc_inst *inst, enum msm_vidc_sub_state sub_state)
> +{
> +	return (inst->sub_state & sub_state);
> +}
Why are there 2 separate funcs for core and inst? Don't we have
a pointer within one to the other?


[...]

> +
> +int msm_vidc_update_state(struct msm_vidc_inst *inst,
> +			  enum msm_vidc_state request_state, const char *func)
> +{
> +	struct msm_vidc_state_handle *state_handle = NULL;
> +	int rc = 0;
rc is unused

[...]

> +static int msm_vidc_set_sub_state(struct msm_vidc_inst *inst,
> +				  enum msm_vidc_sub_state sub_state, const char *func)
> +{
> +	char sub_state_name[MAX_NAME_LENGTH];
> +	int cnt, rc = 0;
ditto

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 16/33] iris: add helpers for media format
  2023-07-28 13:23 ` [PATCH 16/33] iris: add helpers for media format Vikash Garodia
@ 2023-07-28 17:55   ` Konrad Dybcio
  2023-08-14 19:18     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:55 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> Add helpers to calculate stride, scanline, buffer size
> etc. for different media formats.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
[...]


> +
> +#ifndef MSM_MEDIA_ALIGN
> +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\
> +	((((__sz) + (__align) - 1) / (__align)) * (__align)) :\
> +	(((__sz) + (__align) - 1) & (~((__align) - 1))))
<linux/align.h>?

> +#endif
> +
> +#ifndef MSM_MEDIA_ROUNDUP
> +#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r))
> +#endif
> +
> +/*
> + * Function arguments:
> + * @v4l2_fmt
> + * @width
> + * Progressive: width
> + * Interlaced: width
> + */
Kerneldoc would be cooler

[...]

> +static inline unsigned int video_rgb_stride_pix(unsigned int colorformat,
> +						unsigned int width)
> +{
> +	unsigned int bpp = 4;
Always?


Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues
  2023-07-28 13:23 ` [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues Vikash Garodia
@ 2023-07-28 17:58   ` Konrad Dybcio
  2023-08-14 19:19     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 17:58 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> This implements functions to allocate and update the shared memory
> used for sending commands to firmware and receiving messages from
> firmware.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |  89 ++++
>  .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  | 537 +++++++++++++++++++++
>  2 files changed, 626 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
> new file mode 100644
> index 0000000..f533811
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _VENUS_HFI_QUEUE_H_
> +#define _VENUS_HFI_QUEUE_H_
> +
> +#include <linux/types.h>
> +
> +#include "msm_vidc_internal.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		0
> +#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q		1
> +#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q		2
> +#define HFI_MASK_QHDR_STATUS			0x000000ff
GENMASK, BIT()..

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 05/33] iris: vidc: add vb2 ops
  2023-07-28 13:23 ` [PATCH 05/33] iris: vidc: add vb2 ops Vikash Garodia
@ 2023-07-28 18:03   ` Nicolas Dufresne
  2023-08-14 19:03     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Nicolas Dufresne @ 2023-07-28 18:03 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

Le vendredi 28 juillet 2023 à 18:53 +0530, Vikash Garodia a écrit :
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements vb2 ops for streaming modes for
> alloc, free, map and unmap buffers.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |  39 ++
>  .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     | 605 +++++++++++++++++++++
>  2 files changed, 644 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
> new file mode 100644
> index 0000000..12378ce
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_VB2_H_
> +#define _MSM_VIDC_VB2_H_
> +
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-v4l2.h>
> +
> +#include "msm_vidc_inst.h"
> +
> +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
> +				    u32 type, const char *func);
> +
> +/* vb2_mem_ops */
> +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
> +		    unsigned long size);
> +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
> +			    struct dma_buf *dbuf, unsigned long size);
> +
> +void msm_vb2_put(void *buf_priv);
> +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma);
> +void msm_vb2_detach_dmabuf(void *buf_priv);
> +int msm_vb2_map_dmabuf(void *buf_priv);
> +void msm_vb2_unmap_dmabuf(void *buf_priv);
> +
> +/* vb2_ops */
> +int msm_vb2_queue_setup(struct vb2_queue *q,
> +			unsigned int *num_buffers, unsigned int *num_planes,
> +			unsigned int sizes[], struct device *alloc_devs[]);
> +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
> +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
> +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count);
> +void msm_vb2_stop_streaming(struct vb2_queue *q);
> +void msm_vb2_buf_queue(struct vb2_buffer *vb2);
> +#endif // _MSM_VIDC_VB2_H_
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
> new file mode 100644
> index 0000000..c936d95
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
> @@ -0,0 +1,605 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "msm_vdec.h"
> +#include "msm_venc.h"
> +#include "msm_vidc_control.h"
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_inst.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_platform.h"
> +#include "msm_vidc_power.h"
> +#include "msm_vidc_vb2.h"
> +
> +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
> +				    u32 type, const char *func)
> +{
> +	struct vb2_queue *q = NULL;
> +
> +	if (type == INPUT_MPLANE) {
> +		q = inst->bufq[INPUT_PORT].vb2q;
> +	} else if (type == OUTPUT_MPLANE) {
> +		q = inst->bufq[OUTPUT_PORT].vb2q;
> +	} else {
> +		i_vpr_e(inst, "%s: invalid buffer type %d\n",
> +			__func__, type);
> +	}
> +	return q;
> +}
> +
> +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
> +		    unsigned long size)
> +{
> +	return (void *)0xdeadbeef;
> +}
> +
> +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
> +			    struct dma_buf *dbuf, unsigned long size)
> +{
> +	struct msm_vidc_inst *inst;
> +	struct msm_vidc_core *core;
> +	struct msm_vidc_buffer *buf = NULL;
> +	struct msm_vidc_buffer *ro_buf, *dummy;
> +
> +	if (!vb || !dev || !dbuf || !vb->vb2_queue) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return NULL;
> +	}
> +	inst = vb->vb2_queue->drv_priv;
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
> +		return NULL;
> +	}
> +	core = inst->core;
> +
> +	buf = msm_vidc_fetch_buffer(inst, vb);
> +	if (!buf) {
> +		i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__);
> +		buf = NULL;
> +		goto exit;
> +	}
> +	buf->inst = inst;
> +	buf->dmabuf = dbuf;
> +
> +	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
> +			if (ro_buf->dmabuf != buf->dmabuf)
> +				continue;
> +			print_vidc_buffer(VIDC_LOW, "low ", "attach: found ro buf", inst, ro_buf);
> +			buf->attach = ro_buf->attach;
> +			ro_buf->attach = NULL;
> +			goto exit;
> +		}
> +	}
> +
> +	buf->attach = call_mem_op(core, dma_buf_attach, core, dbuf, dev);
> +	if (!buf->attach) {
> +		buf->attach = NULL;
> +		buf = NULL;
> +		goto exit;
> +	}
> +	print_vidc_buffer(VIDC_LOW, "low ", "attach", inst, buf);
> +
> +exit:
> +	if (!buf)
> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
> +	put_inst(inst);
> +	return buf;
> +}
> +
> +void msm_vb2_put(void *buf_priv)
> +{
> +}
> +
> +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
> +{
> +	return 0;
> +}
> +
> +void msm_vb2_detach_dmabuf(void *buf_priv)
> +{
> +	struct msm_vidc_buffer *vbuf = buf_priv;
> +	struct msm_vidc_buffer *ro_buf, *dummy;
> +	struct msm_vidc_core *core;
> +	struct msm_vidc_inst *inst;
> +
> +	if (!vbuf || !vbuf->inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +	inst = vbuf->inst;
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
> +		return;
> +	}
> +	core = inst->core;
> +
> +	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
> +			if (ro_buf->dmabuf != vbuf->dmabuf)
> +				continue;
> +			print_vidc_buffer(VIDC_LOW, "low ", "detach: found ro buf", inst, ro_buf);
> +			ro_buf->attach = vbuf->attach;
> +			vbuf->attach = NULL;
> +			goto exit;
> +		}
> +	}
> +
> +	print_vidc_buffer(VIDC_LOW, "low ", "detach", inst, vbuf);
> +	if (vbuf->attach && vbuf->dmabuf) {
> +		call_mem_op(core, dma_buf_detach, core, vbuf->dmabuf, vbuf->attach);
> +		vbuf->attach = NULL;
> +	}
> +
> +exit:
> +	vbuf->dmabuf = NULL;
> +	vbuf->inst = NULL;
> +}
> +
> +int msm_vb2_map_dmabuf(void *buf_priv)
> +{
> +	int rc = 0;
> +	struct msm_vidc_buffer *buf = buf_priv;
> +	struct msm_vidc_core *core;
> +	struct msm_vidc_inst *inst;
> +	struct msm_vidc_buffer *ro_buf, *dummy;
> +
> +	if (!buf || !buf->inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +	inst = buf->inst;
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +	core = inst->core;
> +
> +	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
> +			if (ro_buf->dmabuf != buf->dmabuf)
> +				continue;
> +			print_vidc_buffer(VIDC_LOW, "low ", "map: found ro buf", inst, ro_buf);
> +			buf->sg_table = ro_buf->sg_table;
> +			buf->device_addr = ro_buf->device_addr;
> +			ro_buf->sg_table = NULL;
> +			goto exit;
> +		}
> +	}
> +
> +	buf->sg_table = call_mem_op(core, dma_buf_map_attachment, core, buf->attach);
> +	if (!buf->sg_table || !buf->sg_table->sgl) {
> +		buf->sg_table = NULL;
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +	buf->device_addr = sg_dma_address(buf->sg_table->sgl);
> +	print_vidc_buffer(VIDC_HIGH, "high", "map", inst, buf);
> +
> +exit:
> +	if (rc)
> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
> +	put_inst(inst);
> +	return rc;
> +}
> +
> +void msm_vb2_unmap_dmabuf(void *buf_priv)
> +{
> +	struct msm_vidc_buffer *vbuf = buf_priv;
> +	struct msm_vidc_buffer *ro_buf, *dummy;
> +	struct msm_vidc_core *core;
> +	struct msm_vidc_inst *inst;
> +
> +	if (!vbuf || !vbuf->inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +	inst = vbuf->inst;
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
> +		return;
> +	}
> +	core = inst->core;
> +
> +	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
> +			if (ro_buf->dmabuf != vbuf->dmabuf)
> +				continue;
> +			print_vidc_buffer(VIDC_LOW, "low ", "unmap: found ro buf", inst, ro_buf);
> +			ro_buf->sg_table = vbuf->sg_table;
> +			vbuf->sg_table = NULL;
> +			vbuf->device_addr = 0x0;
> +			goto exit;
> +		}
> +	}
> +
> +	print_vidc_buffer(VIDC_HIGH, "high", "unmap", inst, vbuf);
> +	if (vbuf->attach && vbuf->sg_table) {
> +		call_mem_op(core, dma_buf_unmap_attachment, core, vbuf->attach, vbuf->sg_table);
> +		vbuf->sg_table = NULL;
> +		vbuf->device_addr = 0x0;
> +	}
> +
> +exit:
> +	return;
> +}
> +
> +int msm_vb2_queue_setup(struct vb2_queue *q,
> +			unsigned int *num_buffers, unsigned int *num_planes,
> +			unsigned int sizes[], struct device *alloc_devs[])
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +	struct msm_vidc_core *core;
> +	int port;
> +	struct v4l2_format *f;
> +	enum msm_vidc_buffer_type buffer_type = 0;
> +	enum msm_vidc_buffer_region region = MSM_VIDC_REGION_NONE;
> +	struct context_bank_info *cb = NULL;
> +	struct msm_vidc_buffers *buffers;
> +
> +	if (!q || !num_buffers || !num_planes ||
> +	    !sizes || !q->drv_priv) {
> +		d_vpr_e("%s: invalid params, q = %pK, %pK, %pK\n",
> +			__func__, q, num_buffers, num_planes);
> +		return -EINVAL;
> +	}
> +	inst = q->drv_priv;
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
> +		return -EINVAL;
> +	}
> +	core = inst->core;
> +
> +	if (is_state(inst, MSM_VIDC_STREAMING)) {
> +		i_vpr_e(inst, "%s: invalid state %d\n", __func__, inst->state);
> +		return -EINVAL;
> +	}
> +
> +	port = v4l2_type_to_driver_port(inst, q->type, __func__);
> +	if (port < 0)
> +		return -EINVAL;
> +
> +	/* prepare dependency list once per session */
> +	if (!inst->caps_list_prepared) {
> +		rc = msm_vidc_prepare_dependency_list(inst);
> +		if (rc)
> +			return rc;
> +		inst->caps_list_prepared = true;
> +	}
> +
> +	/* adjust v4l2 properties for master port */
> +	if ((is_encode_session(inst) && port == OUTPUT_PORT) ||
> +	    (is_decode_session(inst) && port == INPUT_PORT)) {
> +		rc = msm_vidc_adjust_v4l2_properties(inst);
> +		if (rc) {
> +			i_vpr_e(inst, "%s: failed to adjust properties\n", __func__);
> +			return rc;
> +		}
> +	}
> +
> +	if (*num_planes && (port == INPUT_PORT || port == OUTPUT_PORT)) {
> +		f = &inst->fmts[port];
> +		if (*num_planes != f->fmt.pix_mp.num_planes) {
> +			i_vpr_e(inst, "%s: requested num_planes %d not supported %d\n",
> +				__func__, *num_planes, f->fmt.pix_mp.num_planes);
> +			return -EINVAL;
> +		}
> +		if (sizes[0] < inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage) {
> +			i_vpr_e(inst, "%s: requested size %d not acceptable\n",
> +				__func__, sizes[0]);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	buffer_type = v4l2_type_to_driver(q->type, __func__);
> +	if (!buffer_type)
> +		return -EINVAL;
> +
> +	rc = msm_vidc_free_buffers(inst, buffer_type);
> +	if (rc) {
> +		i_vpr_e(inst, "%s: failed to free buffers, type %s\n",
> +			__func__, v4l2_type_name(q->type));
> +		return rc;
> +	}
> +
> +	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
> +	if (!buffers)
> +		return -EINVAL;
> +
> +	buffers->min_count = call_session_op(core, min_count, inst, buffer_type);
> +	buffers->extra_count = call_session_op(core, extra_count, inst, buffer_type);
> +	if (*num_buffers < buffers->min_count + buffers->extra_count)
> +		*num_buffers = buffers->min_count + buffers->extra_count;
> +	buffers->actual_count = *num_buffers;
> +	*num_planes = 1;
> +
> +	buffers->size = call_session_op(core, buffer_size, inst, buffer_type);
> +
> +	inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage = buffers->size;
> +	sizes[0] = inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage;
> +
> +	rc = msm_vidc_allocate_buffers(inst, buffer_type, *num_buffers);
> +	if (rc) {
> +		i_vpr_e(inst, "%s: failed to allocate buffers, type %s\n",
> +			__func__, v4l2_type_name(q->type));
> +		return rc;
> +	}
> +
> +	region = call_mem_op(core, buffer_region, inst, buffer_type);
> +	cb = msm_vidc_get_context_bank_for_region(core, region);
> +	if (!cb) {
> +		d_vpr_e("%s: Failed to get context bank device\n",
> +			__func__);
> +		return -EIO;
> +	}
> +	q->dev = cb->dev;
> +
> +	i_vpr_h(inst,
> +		"queue_setup: type %s num_buffers %d sizes[0] %d cb %s\n",
> +		v4l2_type_name(q->type), *num_buffers, sizes[0], cb->name);
> +	return rc;
> +}
> +
> +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +
> +	if (!q || !q->drv_priv) {
> +		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
> +		return -EINVAL;
> +	}
> +	inst = q->drv_priv;
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q);
> +	if (rc) {
> +		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
> +		goto exit;
> +	}
> +
> +exit:
> +	return rc;
> +}
> +
> +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
> +{
> +	enum msm_vidc_buffer_type buf_type;
> +	int rc = 0;
> +
> +	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
> +		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
> +		return -EINVAL;
> +	}
> +	if (!is_decode_session(inst) && !is_encode_session(inst)) {
> +		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
> +		return -EINVAL;
> +	}
> +	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
> +
> +	if (!inst->once_per_session_set) {

This seems miss-placed, I think you should be able to move this into your driver
open() call and drop the inst->once_per_session_set boolean.

> +		inst->once_per_session_set = true;
> +		rc = msm_vidc_session_set_codec(inst);
> +		if (rc)
> +			return rc;
> +
> +		if (is_encode_session(inst)) {
> +			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
> +								       MSM_VIDC_BUF_ARP);
> +			if (rc)
> +				return rc;
> +		} else if (is_decode_session(inst)) {
> +			rc = msm_vidc_session_set_default_header(inst);
> +			if (rc)
> +				return rc;
> +
> +			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
> +								       MSM_VIDC_BUF_PERSIST);
> +			if (rc)
> +				return rc;
> +		}
> +	}
> +
> +	if (is_decode_session(inst))
> +		inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
> +
> +	msm_vidc_allow_dcvs(inst);
> +	msm_vidc_power_data_reset(inst);
> +
> +	if (q->type == INPUT_MPLANE) {
> +		if (is_decode_session(inst))
> +			rc = msm_vdec_streamon_input(inst);
> +		else if (is_encode_session(inst))
> +			rc = msm_venc_streamon_input(inst);
> +	} else if (q->type == OUTPUT_MPLANE) {
> +		if (is_decode_session(inst))
> +			rc = msm_vdec_streamon_output(inst);
> +		else if (is_encode_session(inst))
> +			rc = msm_venc_streamon_output(inst);
> +	}
> +	if (rc)
> +		return rc;
> +
> +	/* print final buffer counts & size details */
> +	msm_vidc_print_buffer_info(inst);
> +
> +	/* print internal buffer memory usage stats */
> +	msm_vidc_print_memory_stats(inst);
> +
> +	buf_type = v4l2_type_to_driver(q->type, __func__);
> +	if (!buf_type)
> +		return -EINVAL;
> +
> +	/* queue pending buffers */
> +	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
> +	if (rc)
> +		return rc;
> +
> +	/* initialize statistics timer(one time) */
> +	if (!inst->stats.time_ms)
> +		inst->stats.time_ms = ktime_get_ns() / 1000 / 1000;
> +
> +	/* schedule to print buffer statistics */
> +	rc = schedule_stats_work(inst);
> +	if (rc)
> +		return rc;
> +
> +	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
> +	    (q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
> +		rc = msm_vidc_get_properties(inst);
> +		if (rc)
> +			return rc;
> +	}
> +
> +	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
> +	return rc;
> +}
> +
> +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
> +{
> +	int rc = 0;
> +
> +	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
> +		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
> +		return -EINVAL;
> +	}
> +	if (!is_decode_session(inst) && !is_encode_session(inst)) {
> +		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
> +		return -EINVAL;
> +	}
> +	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
> +
> +	if (q->type == INPUT_MPLANE) {
> +		if (is_decode_session(inst))
> +			rc = msm_vdec_streamoff_input(inst);
> +		else if (is_encode_session(inst))
> +			rc = msm_venc_streamoff_input(inst);
> +	} else if (q->type == OUTPUT_MPLANE) {
> +		if (is_decode_session(inst))
> +			rc = msm_vdec_streamoff_output(inst);
> +		else if (is_encode_session(inst))
> +			rc = msm_venc_streamoff_output(inst);
> +	}
> +	if (rc)
> +		return rc;
> +
> +	/* Input port streamoff */
> +	if (q->type == INPUT_MPLANE) {
> +		/* flush timestamps list */
> +		msm_vidc_flush_ts(inst);
> +	}
> +
> +	/* print internal buffer memory usage stats */
> +	msm_vidc_print_memory_stats(inst);
> +
> +	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
> +	return rc;
> +}
> +
> +void msm_vb2_stop_streaming(struct vb2_queue *q)
> +{
> +	struct msm_vidc_inst *inst;
> +	int rc = 0;
> +
> +	if (!q || !q->drv_priv) {
> +		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
> +		return;
> +	}
> +	inst = q->drv_priv;
> +	if (!inst) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +
> +	rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q);
> +	if (rc) {
> +		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
> +	}
> +}
> +
> +void msm_vb2_buf_queue(struct vb2_buffer *vb2)
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +	struct dma_buf *dbuf = NULL;
> +	struct msm_vidc_core *core;
> +	u64 ktime_ns = ktime_get_ns();
> +
> +	if (!vb2) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +
> +	inst = vb2_get_drv_priv(vb2->vb2_queue);
> +	if (!inst || !inst->core) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return;
> +	}
> +	core = inst->core;
> +
> +	if (!vb2->planes[0].bytesused) {
> +		if (vb2->type == INPUT_MPLANE) {
> +			/* Expecting non-zero filledlen on INPUT port */
> +			i_vpr_e(inst,
> +				"%s: zero bytesused input buffer not supported\n", __func__);
> +			rc = -EINVAL;
> +			goto exit;
> +		}
> +	}
> +
> +	inst->last_qbuf_time_ns = ktime_ns;
> +
> +	if (vb2->type == INPUT_MPLANE) {
> +		rc = msm_vidc_update_input_rate(inst, div_u64(ktime_ns, 1000));
> +		if (rc)
> +			goto exit;
> +	}
> +
> +	/*
> +	 * Userspace may close fd(from other thread), before driver attempts to call
> +	 * dma_buf_get() in qbuf(FTB) sequence(for decoder output buffer) which may
> +	 * lead to different kind of security issues. Add check to compare if dma_buf
> +	 * address is matching with driver dma_buf_get returned address for that fd.
> +	 */
> +
> +	dbuf = call_mem_op(core, dma_buf_get, inst, vb2->planes[0].m.fd);
> +	if (dbuf != vb2->planes[0].dbuf) {
> +		i_vpr_e(inst, "%s: invalid dmabuf address 0x%p expected 0x%p\n",
> +			__func__, dbuf, vb2->planes[0].dbuf);
> +		rc = -EINVAL;
> +		goto exit;
> +	}
> +
> +	if (is_decode_session(inst))
> +		rc = msm_vdec_qbuf(inst, vb2);
> +	else if (is_encode_session(inst))
> +		rc = msm_venc_qbuf(inst, vb2);
> +	else
> +		rc = -EINVAL;
> +	if (rc) {
> +		print_vb2_buffer("failed vb2-qbuf", inst, vb2);
> +		goto exit;
> +	}
> +
> +exit:
> +	if (dbuf)
> +		call_mem_op(core, dma_buf_put, inst, dbuf);
> +
> +	if (rc) {
> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
> +		vb2_buffer_done(vb2, VB2_BUF_STATE_ERROR);
> +	}
> +}


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth
  2023-07-28 13:23 ` [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth Vikash Garodia
@ 2023-07-28 18:09   ` Konrad Dybcio
  2023-08-14 19:21     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 18:09 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the logic to compute bus bandwidth required by encoder
> or decoder for a specific usecase. It takes input as various video
> usecase parameters as configured by clients.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
[...]

> +/* 100x */
> +static u32 dpbopb_ubwc30_cr_table_cratio_iris3[7][12] = {
const?

[...]

> +
> +	llc_enabled_ref_y_rd = (codec_input.status_llc_onoff) ? 1 : 0;
> +	llc_enable_ref_crcb_rd = (codec_input.status_llc_onoff) ? 1 : 0;
> +	/* H265D BSE tlb in LLC will be pored in Kailua */
?

> +	llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0;
"? 1 : 0" is fancy bool conversion (!!x)

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency
  2023-07-28 13:23 ` [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency Vikash Garodia
@ 2023-07-28 18:13   ` Konrad Dybcio
  2023-08-14 19:25     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Konrad Dybcio @ 2023-07-28 18:13 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm
  Cc: quic_dikshita

On 28.07.2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the logic to computer the required clock frequency
> by encoder or decoder for a specific usecase. It considers the input
> as various parameters configured by client for that usecase.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  | 627 +++++++++++++++++++++
>  1 file changed, 627 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
> 
> diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
> new file mode 100644
> index 0000000..6665aef
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
> @@ -0,0 +1,627 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "msm_vidc_debug.h"
> +
> +#define ENABLE_FINEBITRATE_SUBUHD60 0
> +#include "perf_static_model.h"
> +
> +/*
> + * Chipset Generation Technology: SW/FW overhead profiling
> + * need update with new numbers
> + */
> +static u32 frequency_table_iris3[2][6] = {
I think it's the third repetition of the same (ftbl + OPP)

> +	/* //make lowsvs_D1 as invalid; */
> +	{533, 444, 366, 338, 240, 0},
> +	{800, 666, 549, 507, 360, 0},
> +};
> +
> + /* Tensilica cycles */
> +#define DECODER_VPP_FW_OVERHEAD_IRIS3                                                  66234
> +
> +/* Tensilica cycles; this is measured in Lahaina 1stage with FW profiling */
Is it gonna differ for other SoCs? Especially that 8350 has IRIS2?

> +#define DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3                                         93000
> +
> +#define DECODER_VSP_FW_OVERHEAD_IRIS3 \
> +	(DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 - DECODER_VPP_FW_OVERHEAD_IRIS3)
> +
> +/* Tensilica cycles; encoder has ARP register */
> +#define ENCODER_VPP_FW_OVERHEAD_IRIS3                                                  48405
> +
> +#define ENCODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 \
> +	(ENCODER_VPP_FW_OVERHEAD_IRIS3 + DECODER_VSP_FW_OVERHEAD_IRIS3)
> +
> +#define DECODER_SW_OVERHEAD_IRIS3                                                      489583
> +#define ENCODER_SW_OVERHEAD_IRIS3                                                      489583
> +
> +/* Video IP Core Technology: pipefloor and pipe penlaty */
> +static u32 decoder_vpp_target_clk_per_mb_iris3 = 200;
Why is this a variable?

[...]

> +
> +/* 8KUHD60; UHD240; 1080p960  with B */
> +static u32 fp_pixel_count_bar0 = 3840 * 2160 * 240;
> +/* 8KUHD60; UHD240; 1080p960  without B */
> +static u32 fp_pixel_count_bar1 = 3840 * 2160 * 240;
Not sure what the 'B' is, but the entries are the same. And looks like
there's:

- no need for it to be a variable
- maybe you could make this a macro or just a simple multiplication

[...]

> +u32 get_bitrate_entry(u32 pixle_count)
pixle -> pixel, checkpatch should point out typos

[...]

> +static int calculate_vsp_min_freq(struct api_calculation_input codec_input,
> +				  struct api_calculation_freq_output *codec_output)
> +{
> +	/*
> +	 * VSP calculation
> +	 * different methodology from Lahaina
> +	 */
Not sure if that comment is useful to the reader.

[...]


> +
> +static u32 calculate_pipe_penalty(struct api_calculation_input codec_input)
> +{
> +	u32 pipe_penalty_codec = 0;
> +
> +	/* decoder */
> +	if (codec_input.decoder_or_encoder == CODEC_DECODER)
> +		pipe_penalty_codec = pipe_penalty_iris3[0][0];
> +	else
> +		pipe_penalty_codec = 101;
Add a define for this magic number?

Also, return the value instead of assigning it and doing the same


Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver
  2023-07-28 13:23 ` [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver Vikash Garodia
@ 2023-07-28 22:48   ` Randy Dunlap
  2023-08-14 18:44     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Randy Dunlap @ 2023-07-28 22:48 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita



On 7/28/23 06:23, Vikash Garodia wrote:
> Add an entry for Iris video encoder/decoder accelerator driver.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  MAINTAINERS | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3be1bdf..ea633b2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17671,6 +17671,16 @@ T:	git git://linuxtv.org/media_tree.git
>  F:	Documentation/devicetree/bindings/media/*venus*
>  F:	drivers/media/platform/qcom/venus/
>  
> +QUALCOMM IRIS VIDEO ACCELERATOR DRIVER

This entry should immediately follow:
QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER

to keep the file in alphabetical order.

> +M:	Vikash Garodia <quic_vgarodia@quicinc.com>
> +M:	Dikshita Agarwal <quic_dikshita@quicinc.com>
> +L:	linux-media@vger.kernel.org
> +L:	linux-arm-msm@vger.kernel.org
> +S:	Maintained
> +T:	git git://linuxtv.org/media_tree.git
> +F:	Documentation/devicetree/bindings/media/qcom,*-iris.yaml
> +F:	drivers/media/platform/qcom/iris/
> +
>  QUALCOMM WCN36XX WIRELESS DRIVER
>  M:	Loic Poulain <loic.poulain@linaro.org>
>  L:	wcn36xx@lists.infradead.org

-- 
~Randy

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI)
  2023-07-28 13:23 ` [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI) Vikash Garodia
  2023-07-28 15:58   ` Bryan O'Donoghue
@ 2023-07-31  9:02   ` Bryan O'Donoghue
  2023-08-14 19:11     ` Dikshita Agarwal
  1 sibling, 1 reply; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-07-31  9:02 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 14:23, Vikash Garodia wrote:
> This implements the interface for communication between
> host driver and firmware through interface commands and messages.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>

More dead code here

drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:542:	//if 
(core->last_packet_type != HFI_CMD_SYS_PC_PREP)
drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:543:	// 
core->skip_pc_count = 0;

---
bod


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
                     ` (2 preceding siblings ...)
  2023-07-28 13:49   ` Dmitry Baryshkov
@ 2023-07-31 21:16   ` Krzysztof Kozlowski
  2023-08-14 18:54     ` Dikshita Agarwal
  2023-07-31 21:23   ` Krzysztof Kozlowski
  4 siblings, 1 reply; 108+ messages in thread
From: Krzysztof Kozlowski @ 2023-07-31 21:16 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the platform driver methods, file
> operations and v4l2 registration.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660 +++++++++++++++++++++
>  1 file changed, 660 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> new file mode 100644
> index 0000000..43439cb
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> @@ -0,0 +1,660 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iommu.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/stringify.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_memory.h"
> +#include "msm_vidc_platform.h"
> +#include "msm_vidc_state.h"
> +#include "venus_hfi.h"
> +
> +#define BASE_DEVICE_NUMBER 32
> +
> +struct msm_vidc_core *g_core;
> +
> +static inline bool is_video_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));

Where is it documented? Are you 100% sure that checkpatch does not complain?

I is also a bit surprising to see of_device_is_compatible inside the
code in some random place. How does it scale? Any driver data and
variant checks should be done via helpers and driver data, not putting
compatibles in multiple places.


> +}
> +
> +static inline bool is_video_context_bank_device(struct device *dev)
> +{
> +	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
> +}
> +
> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
> +{
> +	struct msm_vidc_resource *res = NULL;
> +	int rc = 0;
> +
> +	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
> +	if (!res) {
> +		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
> +		return -ENOMEM;
> +	}
> +	core->resource = res;
> +
> +	rc = call_res_op(core, init, core);
> +	if (rc) {
> +		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id msm_vidc_dt_match[] = {
> +	{.compatible = "qcom,sm8550-vidc"},
> +	{.compatible = "qcom,vidc,cb-ns"},

No, srsly, where did you document it?

If this is not suitable for upstreaming (as it looks like) mark it as
RFC, so we will know it that you did not run checkpatch...


> +	MSM_VIDC_EMPTY_BRACE
> +};
> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
> +
> +static void msm_vidc_release_video_device(struct video_device *vdev)
> +{
> +	d_vpr_e("%s: video device released\n", __func__);

And why would you ever print anything here? What's wrong with tracing?

> +}

...

> +
> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
> +{
> +	int rc = 0;
> +	struct msm_vidc_core *core = NULL;
> +	int nr = BASE_DEVICE_NUMBER;
> +
> +	d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));

No debug prints reinventing tracing.

> +
> +	core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL);
> +	if (!core) {
> +		d_vpr_e("%s: failed to alloc memory for core\n", __func__);

Ooops, this for sure did not pass any checks by tools. Sorry, please run
basic checks like coccinelle, smatch, sparse, W=1 builds.

> +		return -ENOMEM;
> +	}
> +	g_core = core;
> +
> +	core->pdev = pdev;
> +	dev_set_drvdata(&pdev->dev, core);
> +
> +	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
> +	if (!core->debugfs_parent)
> +		d_vpr_h("Failed to create debugfs for msm_vidc\n");
> +
> +	rc = msm_vidc_devm_init_core(&pdev->dev, core);
> +	if (rc) {
> +		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
> +		goto init_core_failed;
> +	}
> +
> +	rc = msm_vidc_init_platform(core);
> +	if (rc) {
> +		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
> +		rc = -EINVAL;
> +		goto init_plat_failed;
> +	}
> +
> +	rc = msm_vidc_init_resources(core);
> +	if (rc) {
> +		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
> +		goto init_res_failed;
> +	}
> +
> +	rc = msm_vidc_init_core_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
> +		goto init_res_failed;
> +	}
> +
> +	rc = msm_vidc_init_instance_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
> +		goto init_inst_caps_fail;
> +	}
> +
> +	core->debugfs_root = msm_vidc_debugfs_init_core(core);
> +	if (!core->debugfs_root)
> +		d_vpr_h("Failed to init debugfs core\n");
> +
> +	d_vpr_h("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.
> +	 */
> +	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
> +				  &pdev->dev);
> +	if (rc) {
> +		d_vpr_e("Failed to trigger probe for sub-devices\n");
> +		goto sub_dev_failed;
> +	}
> +
> +	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
> +	if (rc) {
> +		d_vpr_e("Failed to register v4l2 device\n");
> +		goto v4l2_reg_failed;
> +	}
> +
> +	/* setup the decoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
> +	if (rc) {
> +		d_vpr_e("Failed to register video decoder\n");
> +		goto dec_reg_failed;
> +	}
> +
> +	/* setup the encoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
> +	if (rc) {
> +		d_vpr_e("Failed to register video encoder\n");
> +		goto enc_reg_failed;
> +	}
> +
> +	rc = venus_hfi_queue_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: interface queues init failed\n", __func__);
> +		goto queues_init_failed;
> +	}
> +
> +	rc = msm_vidc_core_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: sys init failed\n", __func__);
> +		goto core_init_failed;
> +	}
> +
> +	d_vpr_h("%s(): succssful\n", __func__);
> +
> +	return rc;
> +
> +core_init_failed:
> +	venus_hfi_queue_deinit(core);
> +queues_init_failed:
> +	of_platform_depopulate(&pdev->dev);
> +sub_dev_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> +enc_reg_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> +dec_reg_failed:
> +	v4l2_device_unregister(&core->v4l2_dev);
> +v4l2_reg_failed:
> +init_inst_caps_fail:
> +init_res_failed:
> +init_plat_failed:
> +init_core_failed:
> +	dev_set_drvdata(&pdev->dev, NULL);
> +	g_core = NULL;
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
> +{
> +	struct msm_vidc_core *core = NULL;
> +	int rc = 0;
> +
> +	if (!pdev) {
> +		d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
> +		return -EINVAL;
> +	} else if (!pdev->dev.parent) {
> +		d_vpr_e("%s: Failed to find a parent for %s\n",
> +			__func__, dev_name(&pdev->dev));
> +		return -ENODEV;
> +	}
> +
> +	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
> +
> +	core = dev_get_drvdata(pdev->dev.parent);
> +	if (!core) {
> +		d_vpr_e("%s: core not found in device %s",
> +			__func__, dev_name(pdev->dev.parent));
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_setup_context_bank(core, &pdev->dev);
> +	if (rc) {
> +		d_vpr_e("%s: Failed to probe context bank %s\n",
> +			__func__, dev_name(&pdev->dev));
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +static int msm_vidc_probe(struct platform_device *pdev)
> +{
> +	if (!pdev) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * 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 (is_video_device(&pdev->dev))
> +		return msm_vidc_probe_video_device(pdev);
> +	else if (is_video_context_bank_device(&pdev->dev))
> +		return msm_vidc_probe_context_bank(pdev);
> +
> +	/* How did we end up here? */
> +	WARN_ON(1);
> +	return -EINVAL;
> +}
> +
> +static int msm_vidc_pm_suspend(struct device *dev)
> +{
> +	int rc = 0;
> +	struct msm_vidc_core *core;
> +	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
> +
> +	/*
> +	 * Bail out if
> +	 * - driver possibly not probed yet
> +	 * - not the main device. We don't support power management on
> +	 *   subdevices (e.g. context banks)
> +	 */
> +	if (!dev || !dev->driver || !is_video_device(dev))
> +		return 0;
> +
> +	core = dev_get_drvdata(dev);
> +	if (!core) {
> +		d_vpr_e("%s: invalid core\n", __func__);

How core can be invalid?

> +		return -EINVAL;
> +	}
> +
> +	core_lock(core, __func__);

What's this? Why do you use some custom locking (it's almost never a
good idea)?

> +	allow = msm_vidc_allow_pm_suspend(core);
> +
> +	if (allow == MSM_VIDC_IGNORE) {
> +		d_vpr_h("%s: pm already suspended\n", __func__);

So you have bug in PM runtime code? Runtime PM does not suspend devices
twice.

> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +		rc = 0;
> +		goto unlock;
> +	} else if (allow != MSM_VIDC_ALLOW) {
> +		d_vpr_h("%s: pm suspend not allowed\n", __func__);
> +		rc = 0;
> +		goto unlock;
> +	}
> +
> +	rc = msm_vidc_suspend(core);
> +	if (rc == -EOPNOTSUPP)
> +		rc = 0;
> +	else if (rc)
> +		d_vpr_e("Failed to suspend: %d\n", rc);
> +	else
> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
> +
> +unlock:
> +	core_unlock(core, __func__);
> +	return rc;
> +}
> +

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
                     ` (2 preceding siblings ...)
  2023-07-28 17:50   ` Nicolas Dufresne
@ 2023-07-31 21:23   ` Krzysztof Kozlowski
  2023-08-14 19:00     ` Dikshita Agarwal
  3 siblings, 1 reply; 108+ messages in thread
From: Krzysztof Kozlowski @ 2023-07-31 21:23 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 15:23, Vikash Garodia wrote:
> Here is the implementation of v4l2 wrapper functions for all
> v4l2 IOCTLs.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>  .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>  2 files changed, 1030 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> new file mode 100644
> index 0000000..3766c9d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _MSM_VIDC_V4L2_H_
> +#define _MSM_VIDC_V4L2_H_
> +
> +#include <linux/fs.h>
> +#include <linux/poll.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-ioctl.h>
> +
> +int msm_v4l2_open(struct file *filp);
> +int msm_v4l2_close(struct file *filp);
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap);
> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
> +		      struct v4l2_fmtdesc *f);
> +int msm_v4l2_try_fmt(struct file *file, void *fh,
> +		     struct v4l2_format *f);
> +int msm_v4l2_s_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_g_fmt(struct file *file, void *fh,
> +		   struct v4l2_format *f);
> +int msm_v4l2_s_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_g_selection(struct file *file, void *fh,
> +			 struct v4l2_selection *s);
> +int msm_v4l2_s_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_g_parm(struct file *file, void *fh,
> +		    struct v4l2_streamparm *a);
> +int msm_v4l2_reqbufs(struct file *file, void *fh,
> +		     struct v4l2_requestbuffers *b);
> +int msm_v4l2_querybuf(struct file *file, void *fh,
> +		      struct v4l2_buffer *b);
> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
> +			 struct v4l2_create_buffers *b);
> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
> +			 struct v4l2_buffer *b);
> +int msm_v4l2_qbuf(struct file *file, void *fh,
> +		  struct v4l2_buffer *b);
> +int msm_v4l2_dqbuf(struct file *file, void *fh,
> +		   struct v4l2_buffer *b);
> +int msm_v4l2_streamon(struct file *file, void *fh,
> +		      enum v4l2_buf_type i);
> +int msm_v4l2_streamoff(struct file *file, void *fh,
> +		       enum v4l2_buf_type i);
> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
> +			     const struct v4l2_event_subscription *sub);
> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
> +			       const struct v4l2_event_subscription *sub);
> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_decoder_cmd *enc);
> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_decoder_cmd *dec);
> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
> +			     struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
> +			 struct v4l2_encoder_cmd *enc);
> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
> +			     struct v4l2_frmsizeenum *fsize);
> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
> +				 struct v4l2_frmivalenum *fival);
> +int msm_v4l2_queryctrl(struct file *file, void *fh,
> +		       struct v4l2_queryctrl *ctrl);
> +int msm_v4l2_querymenu(struct file *file, void *fh,
> +		       struct v4l2_querymenu *qmenu);
> +unsigned int msm_v4l2_poll(struct file *filp,
> +			   struct poll_table_struct *pt);
> +void msm_v4l2_m2m_device_run(void *priv);
> +void msm_v4l2_m2m_job_abort(void *priv);
> +
> +#endif // _MSM_VIDC_V4L2_H_
> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> new file mode 100644
> index 0000000..6dfb18b
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
> @@ -0,0 +1,953 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "msm_vidc.h"
> +#include "msm_vidc_core.h"
> +#include "msm_vidc_debug.h"
> +#include "msm_vidc_driver.h"
> +#include "msm_vidc_inst.h"
> +#include "msm_vidc_internal.h"
> +#include "msm_vidc_v4l2.h"
> +
> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
> +{
> +	if (!filp || !filp->private_data)
> +		return NULL;
> +	return container_of(filp->private_data,
> +					struct msm_vidc_inst, fh);
> +}
> +
> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
> +{
> +	int poll = 0;
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);

This does not look like Linux coding style. Don't create your own
abstraction layer over Linux internal API. Use standard Linux functions
which will behave better and scale along with kernel development.

> +		return POLLERR;
> +	}
> +	if (is_session_error(inst)) {
> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);

i_vpr_e is so obvious for every kernel developer... Please, no.

> +		poll = POLLERR;
> +		goto exit;
> +	}
> +
> +	poll = msm_vidc_poll((void *)inst, filp, pt);
> +	if (poll)
> +		goto exit;
> +
> +exit:
> +	put_inst(inst);
> +	return poll;
> +}
> +
> +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 *inst;
> +
> +	inst = msm_vidc_open(core, vid_dev->type);
> +	if (!inst) {
> +		d_vpr_e("Failed to create instance, type = %d\n",
> +			vid_dev->type);
> +		return -ENOMEM;
> +	}
> +	filp->private_data = &inst->fh;
> +	return 0;
> +}
> +
> +int msm_v4l2_close(struct file *filp)
> +{
> +	int rc = 0;
> +	struct msm_vidc_inst *inst;
> +
> +	inst = get_vidc_inst(filp, NULL);
> +	if (!inst) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	rc = msm_vidc_close(inst);
> +	filp->private_data = NULL;
> +	return rc;
> +}
> +
> +int msm_v4l2_querycap(struct file *filp, void *fh,
> +		      struct v4l2_capability *cap)
> +{
> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
> +	int rc = 0;
> +
> +	inst = get_inst_ref(g_core, inst);
> +	if (!inst || !cap) {
> +		d_vpr_e("%s: invalid instance\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	client_lock(inst, __func__);

? So we don't know what's this? Mutex? Spinlock? Own reinvented lock?

> +	inst_lock(inst, __func__);

Neither this?

No, don't create your own abstractions over standard API.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
                     ` (3 preceding siblings ...)
  2023-07-31 21:16   ` Krzysztof Kozlowski
@ 2023-07-31 21:23   ` Krzysztof Kozlowski
  2023-08-14 18:51     ` Dikshita Agarwal
  4 siblings, 1 reply; 108+ messages in thread
From: Krzysztof Kozlowski @ 2023-07-31 21:23 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 15:23, Vikash Garodia wrote:
> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> 
> This implements the platform driver methods, file
> operations and v4l2 registration.


> +
> +	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
> +	if (!core->debugfs_parent)
> +		d_vpr_h("Failed to create debugfs for msm_vidc\n");
> +
> +	rc = msm_vidc_devm_init_core(&pdev->dev, core);
> +	if (rc) {
> +		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
> +		goto init_core_failed;
> +	}
> +
> +	rc = msm_vidc_init_platform(core);
> +	if (rc) {
> +		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
> +		rc = -EINVAL;
> +		goto init_plat_failed;
> +	}
> +
> +	rc = msm_vidc_init_resources(core);
> +	if (rc) {
> +		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
> +		goto init_res_failed;

NAK.

return dev_err_probe.

> +	}
> +
> +	rc = msm_vidc_init_core_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
> +		goto init_res_failed;
> +	}
> +
> +	rc = msm_vidc_init_instance_caps(core);
> +	if (rc) {
> +		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
> +		goto init_inst_caps_fail;
> +	}
> +
> +	core->debugfs_root = msm_vidc_debugfs_init_core(core);
> +	if (!core->debugfs_root)
> +		d_vpr_h("Failed to init debugfs core\n");
> +
> +	d_vpr_h("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.
> +	 */
> +	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
> +				  &pdev->dev);
> +	if (rc) {
> +		d_vpr_e("Failed to trigger probe for sub-devices\n");
> +		goto sub_dev_failed;
> +	}
> +
> +	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
> +	if (rc) {
> +		d_vpr_e("Failed to register v4l2 device\n");
> +		goto v4l2_reg_failed;
> +	}
> +
> +	/* setup the decoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
> +	if (rc) {
> +		d_vpr_e("Failed to register video decoder\n");
> +		goto dec_reg_failed;
> +	}
> +
> +	/* setup the encoder device */
> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
> +	if (rc) {
> +		d_vpr_e("Failed to register video encoder\n");
> +		goto enc_reg_failed;
> +	}
> +
> +	rc = venus_hfi_queue_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: interface queues init failed\n", __func__);
> +		goto queues_init_failed;
> +	}
> +
> +	rc = msm_vidc_core_init(core);
> +	if (rc) {
> +		d_vpr_e("%s: sys init failed\n", __func__);
> +		goto core_init_failed;
> +	}
> +
> +	d_vpr_h("%s(): succssful\n", __func__);

No need, drop.

> +
> +	return rc;
> +
> +core_init_failed:
> +	venus_hfi_queue_deinit(core);
> +queues_init_failed:
> +	of_platform_depopulate(&pdev->dev);
> +sub_dev_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> +enc_reg_failed:
> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> +dec_reg_failed:
> +	v4l2_device_unregister(&core->v4l2_dev);
> +v4l2_reg_failed:
> +init_inst_caps_fail:
> +init_res_failed:
> +init_plat_failed:
> +init_core_failed:

Ykes! No. This code needs more work.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 24/33] iris: vidc: add debug files
  2023-07-28 13:23 ` [PATCH 24/33] iris: vidc: add debug files Vikash Garodia
@ 2023-07-31 21:31   ` Krzysztof Kozlowski
  2023-08-14 19:12     ` Dikshita Agarwal
  0 siblings, 1 reply; 108+ messages in thread
From: Krzysztof Kozlowski @ 2023-07-31 21:31 UTC (permalink / raw)
  To: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

On 28/07/2023 15:23, Vikash Garodia wrote:
> this implements the debugging framework.

Your commit msgs are not helping to understand why do you need it and
what is this doing. Based on this commit description I would ask you to
drop most of this code as it looks useless. Extend the commit msg to
provide proper justification and list of features each unit provides.

Please do not use "This commit/patch", but imperative mood. See longer
explanation here:
https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95

> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> ---
>  .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   | 186 +++++++
>  .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   | 581 +++++++++++++++++++++
>  2 files changed, 767 insertions(+)
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
> 
> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
> new file mode 100644
> index 0000000..ffced01
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
> @@ -0,0 +1,186 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef __MSM_VIDC_DEBUG__
> +#define __MSM_VIDC_DEBUG__
> +
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/types.h>
> +
> +struct msm_vidc_core;
> +struct msm_vidc_inst;
> +
> +#ifndef VIDC_DBG_LABEL
> +#define VIDC_DBG_LABEL "msm_vidc"
> +#endif

Drop these three. Don't re-invent Linux kernel API.

> +
> +/* Allow only 6 prints/sec */
> +#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ)
> +#define VIDC_DBG_SESSION_RATELIMIT_BURST 6
> +
> +#define VIDC_DBG_TAG_INST VIDC_DBG_LABEL ": %4s: %s: "
> +#define VIDC_DBG_TAG_CORE VIDC_DBG_LABEL ": %4s: %08x: %s: "
> +#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: "
> +#define DEFAULT_SID ((u32)-1)
> +
> +#ifndef MSM_VIDC_EMPTY_BRACE
> +#define MSM_VIDC_EMPTY_BRACE {},

That's the funniest code I saw since some time.

> +#endif
> +
> +extern unsigned int msm_vidc_debug;

Nope.

> +extern unsigned int msm_fw_debug;

Nope.

> +extern bool msm_vidc_fw_dump;

Nope.

> +
> +/* do not modify the log message as it is used in test scripts */
> +#define FMT_STRING_SET_CTRL \
> +	"%s: state %s, name %s, id 0x%x value %d\n"
> +#define FMT_STRING_STATE_CHANGE \
> +	"%s: state changed to %s from %s\n"
> +#define FMT_STRING_MSG_SFR \
> +	"SFR Message from FW: %s\n"
> +#define FMT_STRING_FAULT_HANDLER \
> +	"%s: faulting address: %lx\n"
> +#define FMT_STRING_SET_CAP \
> +	"set cap: name: %24s, cap value: %#10x, hfi: %#10llx\n"
> +
> +/* To enable messages OR these values and
> + * echo the result to debugfs file.
> + *
> + * To enable all messages set msm_vidc_debug = 0x101F
> + */
> +
> +enum vidc_msg_prio_drv {
> +	VIDC_ERR        = 0x00000001,
> +	VIDC_HIGH       = 0x00000002,
> +	VIDC_LOW        = 0x00000004,
> +	VIDC_PERF       = 0x00000008,
> +	VIDC_PKT        = 0x00000010,
> +	VIDC_BUS        = 0x00000020,
> +	VIDC_STAT       = 0x00000040,
> +	VIDC_ENCODER    = 0x00000100,
> +	VIDC_DECODER    = 0x00000200,
> +	VIDC_PRINTK     = 0x10000000,
> +	VIDC_FTRACE     = 0x20000000,
> +};
> +
> +enum vidc_msg_prio_fw {
> +	FW_LOW          = 0x00000001,
> +	FW_MED          = 0x00000002,
> +	FW_HIGH         = 0x00000004,
> +	FW_ERROR        = 0x00000008,
> +	FW_FATAL        = 0x00000010,
> +	FW_PERF         = 0x00000020,
> +	FW_CACHE_LOW    = 0x00000100,
> +	FW_CACHE_MED    = 0x00000200,
> +	FW_CACHE_HIGH   = 0x00000400,
> +	FW_CACHE_ERROR  = 0x00000800,
> +	FW_CACHE_FATAL  = 0x00001000,
> +	FW_CACHE_PERF   = 0x00002000,
> +	FW_PRINTK       = 0x10000000,
> +	FW_FTRACE       = 0x20000000,
> +};
> +
> +#define DRV_LOG        (VIDC_ERR | VIDC_PRINTK)
> +#define DRV_LOGSHIFT   (0)
> +#define DRV_LOGMASK    (0x0FFFFFFF)
> +
> +#define FW_LOG         (FW_ERROR | FW_FATAL | FW_PRINTK)
> +#define FW_LOGSHIFT    (0)
> +#define FW_LOGMASK     (0x0FFFFFFF)
> +
> +#define dprintk_inst(__level, __level_str, inst, __fmt, ...) \
> +	do { \
> +		if (inst && (msm_vidc_debug & (__level))) { \
> +			pr_info(VIDC_DBG_TAG_INST __fmt, \
> +				__level_str, \
> +				inst->debug_str, \
> +				##__VA_ARGS__); \
> +		} \
> +	} while (0)
> +
> +#define i_vpr_e(inst, __fmt, ...) dprintk_inst(VIDC_ERR,  "err ", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_i(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_h(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_l(inst, __fmt, ...) dprintk_inst(VIDC_LOW,  "low ", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_p(inst, __fmt, ...) dprintk_inst(VIDC_PERF, "perf", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_t(inst, __fmt, ...) dprintk_inst(VIDC_PKT,  "pkt ", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_b(inst, __fmt, ...) dprintk_inst(VIDC_BUS,  "bus ", inst, __fmt, ##__VA_ARGS__)

NAK for entire interface. Please use standard debugging functions, not
pr_info for everything.

dev_dbg, dev_info, dev_warn, dev_err. Only these.


> +#define i_vpr_s(inst, __fmt, ...) dprintk_inst(VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
> +
> +#define i_vpr_hp(inst, __fmt, ...) \
> +	dprintk_inst(VIDC_HIGH | VIDC_PERF, "high", inst, __fmt, ##__VA_ARGS__)
> +#define i_vpr_hs(inst, __fmt, ...) \
> +	dprintk_inst(VIDC_HIGH | VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
> +> +#define dprintk_core(__level, __level_str, __fmt, ...) \

NAK

> +	do { \
> +		if (msm_vidc_debug & (__level)) { \
> +			pr_info(VIDC_DBG_TAG_CORE __fmt, \
> +				__level_str, \
> +				DEFAULT_SID, \
> +				"codec", \
> +				##__VA_ARGS__); \
> +		} \
> +	} while (0)
> +
> +#define d_vpr_e(__fmt, ...) dprintk_core(VIDC_ERR,  "err ", __fmt, ##__VA_ARGS__)
> +#define d_vpr_h(__fmt, ...) dprintk_core(VIDC_HIGH, "high", __fmt, ##__VA_ARGS__)
> +#define d_vpr_l(__fmt, ...) dprintk_core(VIDC_LOW,  "low ", __fmt, ##__VA_ARGS__)
> +#define d_vpr_p(__fmt, ...) dprintk_core(VIDC_PERF, "perf", __fmt, ##__VA_ARGS__)
> +#define d_vpr_t(__fmt, ...) dprintk_core(VIDC_PKT,  "pkt ", __fmt, ##__VA_ARGS__)
> +#define d_vpr_b(__fmt, ...) dprintk_core(VIDC_BUS,  "bus ", __fmt, ##__VA_ARGS__)
> +#define d_vpr_s(__fmt, ...) dprintk_core(VIDC_STAT, "stat", __fmt, ##__VA_ARGS__)
> +#define d_vpr_hs(__fmt, ...) \
> +	dprintk_core(VIDC_HIGH | VIDC_STAT, "high", __fmt, ##__VA_ARGS__)
> +
> +#define dprintk_ratelimit(__level, __level_str, __fmt, ...) \
> +	do { \
> +		if (msm_vidc_check_ratelimit()) { \
> +			dprintk_core(__level, __level_str, __fmt, ##__VA_ARGS__); \
> +		} \
> +	} while (0)
> +
> +#define dprintk_firmware(__level, __fmt, ...)	\
> +	do { \
> +		if ((msm_fw_debug & (__level)) & FW_PRINTK) { \
> +			pr_info(FW_DBG_TAG __fmt, \
> +				"fw", \
> +				##__VA_ARGS__); \
> +		} \
> +	} while (0)
> +
> +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,
> +};
> +
> +enum msm_vidc_bug_on_error {
> +	MSM_VIDC_BUG_ON_FATAL             = BIT(0),
> +	MSM_VIDC_BUG_ON_NOC               = BIT(1),
> +	MSM_VIDC_BUG_ON_WD_TIMEOUT        = BIT(2),
> +};
> +
> +struct dentry *msm_vidc_debugfs_init_drv(void);
> +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core);
> +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
> +					  struct dentry *parent);
> +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
> +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
> +			     enum msm_vidc_debugfs_event e);
> +int msm_vidc_check_ratelimit(void);
> +
> +static inline bool is_stats_enabled(void)
> +{
> +	return !!(msm_vidc_debug & VIDC_STAT);

...

> +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core)
> +{
> +	struct dentry *dir = NULL;
> +	char debugfs_name[MAX_DEBUGFS_NAME];
> +	struct dentry *parent;
> +
> +	if (!core->debugfs_parent) {
> +		d_vpr_e("%s: invalid params\n", __func__);
> +		goto failed_create_dir;
> +	}
> +	parent = core->debugfs_parent;
> +
> +	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core");
> +	dir = debugfs_create_dir(debugfs_name, parent);
> +	if (IS_ERR_OR_NULL(dir)) {
> +		dir = NULL;
> +		d_vpr_e("Failed to create debugfs for msm_vidc\n");
> +		goto failed_create_dir;
> +	}
> +	if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) {
> +		d_vpr_e("debugfs_create_file: fail\n");
> +		goto failed_create_dir;
> +	}
> +
> +	if (!debugfs_create_file("stats_delay_ms", 0644, dir, core, &stats_delay_fops)) {
> +		d_vpr_e("debugfs_create_file: fail\n");


What is this entire debugfs supposed to provide?



Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-07-28 14:01 ` Dmitry Baryshkov
@ 2023-08-14 12:58   ` Stanimir Varbanov
  2023-08-14 15:00     ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Stanimir Varbanov @ 2023-08-14 12:58 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm
  Cc: quic_dikshita

Hi Dmitry,

On 28.07.23 г. 17:01 ч., Dmitry Baryshkov wrote:
> On 28/07/2023 16:23, Vikash Garodia wrote:
>> This patch series introduces support for Qualcomm new video acceleration
>> hardware architecture, used for video stream decoding/encoding. This 
>> driver
>> is based on new communication protocol between video hardware and 
>> application
>> processor.
>>
>> This driver comes with below capabilities:
>> - V4L2 complaint video driver with M2M and STREAMING capability.
>> - Supports H264, H265, VP9 decoders.
>> - Supports H264, H265 encoders.
> 
> Please describe, why is it impossible to support this hardware in the 
> venus driver. We do not usually add new drivers for the new generations 
> of the hardware, unless it is fully incompatible with the previous 
> generations. Let me point you to camss or drm/msm drivers. They have 
> successfully solved the issue of supporting multiple generations of the 
> hardware in the same driver.
> 
> Unless the "iris3" is completely different from all the previous 
> generations, I strongly suggest spending time on restructuring existing 
> venus driver and then adding support for the new hardware there instead 
> of dumping out something completely new.

AFAIK the major differences are HW IP and firmware interface (by 
firmware interface I mean a protocol, API and API behavior). The 
firmware and its interface has been re-written to align closely with the 
current v4l2 specs for encoders/decoders state machines [1][2]. On the 
other side current mainline Venus driver firmware is following interface 
similar to OpenMAX.

There are incompatibilities between both firmware interfaces which 
cannot easily combined in a common driver. Even if there is a 
possibility to do that it will lead us to a unreadable driver source 
code and maintenance burden.

Vikash, could elaborate more on firmware interface differences.

[1] 
https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html

[2] 
https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-encoder.html

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-08-14 12:58   ` Stanimir Varbanov
@ 2023-08-14 15:00     ` Dmitry Baryshkov
  2023-08-24 15:23       ` Vikash Garodia
  0 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-14 15:00 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Vikash Garodia, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm,
	quic_dikshita

Hi Stan,

On Mon, 14 Aug 2023 at 15:58, Stanimir Varbanov
<stanimir.k.varbanov@gmail.com> wrote:
>
> Hi Dmitry,
>
> On 28.07.23 г. 17:01 ч., Dmitry Baryshkov wrote:
> > On 28/07/2023 16:23, Vikash Garodia wrote:
> >> This patch series introduces support for Qualcomm new video acceleration
> >> hardware architecture, used for video stream decoding/encoding. This
> >> driver
> >> is based on new communication protocol between video hardware and
> >> application
> >> processor.
> >>
> >> This driver comes with below capabilities:
> >> - V4L2 complaint video driver with M2M and STREAMING capability.
> >> - Supports H264, H265, VP9 decoders.
> >> - Supports H264, H265 encoders.
> >
> > Please describe, why is it impossible to support this hardware in the
> > venus driver. We do not usually add new drivers for the new generations
> > of the hardware, unless it is fully incompatible with the previous
> > generations. Let me point you to camss or drm/msm drivers. They have
> > successfully solved the issue of supporting multiple generations of the
> > hardware in the same driver.
> >
> > Unless the "iris3" is completely different from all the previous
> > generations, I strongly suggest spending time on restructuring existing
> > venus driver and then adding support for the new hardware there instead
> > of dumping out something completely new.
>
> AFAIK the major differences are HW IP and firmware interface (by
> firmware interface I mean a protocol, API and API behavior). The
> firmware and its interface has been re-written to align closely with the
> current v4l2 specs for encoders/decoders state machines [1][2]. On the
> other side current mainline Venus driver firmware is following interface
> similar to OpenMAX.
>
> There are incompatibilities between both firmware interfaces which
> cannot easily combined in a common driver. Even if there is a
> possibility to do that it will lead us to a unreadable driver source
> code and maintenance burden.

Thank you for your explanation!

If the hardware is more or less the same, then the existing venus
driver should be refactored and split into hardware driver and the
firmware interface. Then iris3 can come up as a second driver
implementing support for new firmware interface but utilising common
hardware-related code.

> Vikash, could elaborate more on firmware interface differences.

Do we have any details on firmware versions that implement older
(OpenMAX-like) interface vs versions implementing new (v4l2-like)
interface?

> [1]
> https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html
>
> [2]
> https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-encoder.html

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver
  2023-07-28 22:48   ` Randy Dunlap
@ 2023-08-14 18:44     ` Dikshita Agarwal
  2023-08-16 12:00       ` Bryan O'Donoghue
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:44 UTC (permalink / raw)
  To: Randy Dunlap, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/29/2023 4:18 AM, Randy Dunlap wrote:
> 
> 
> On 7/28/23 06:23, Vikash Garodia wrote:
>> Add an entry for Iris video encoder/decoder accelerator driver.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  MAINTAINERS | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 3be1bdf..ea633b2 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -17671,6 +17671,16 @@ T:	git git://linuxtv.org/media_tree.git
>>  F:	Documentation/devicetree/bindings/media/*venus*
>>  F:	drivers/media/platform/qcom/venus/
>>  
>> +QUALCOMM IRIS VIDEO ACCELERATOR DRIVER
> 
> This entry should immediately follow:
> QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER
> 
> to keep the file in alphabetical order.
> 
Sure, will fix this in next version.

Thanks,
Dikshita

>> +M:	Vikash Garodia <quic_vgarodia@quicinc.com>
>> +M:	Dikshita Agarwal <quic_dikshita@quicinc.com>
>> +L:	linux-media@vger.kernel.org
>> +L:	linux-arm-msm@vger.kernel.org
>> +S:	Maintained
>> +T:	git git://linuxtv.org/media_tree.git
>> +F:	Documentation/devicetree/bindings/media/qcom,*-iris.yaml
>> +F:	drivers/media/platform/qcom/iris/
>> +
>>  QUALCOMM WCN36XX WIRELESS DRIVER
>>  M:	Loic Poulain <loic.poulain@linaro.org>
>>  L:	wcn36xx@lists.infradead.org
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:45   ` Konrad Dybcio
@ 2023-08-14 18:49     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:49 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 7:15 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the platform driver methods, file
>> operations and v4l2 registration.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> [...]
> 
>> +struct msm_vidc_core *g_core;
>> +
>> +static inline bool is_video_device(struct device *dev)
>> +{
>> +	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
>> +}
> Are you expecting this to be expanded each time support for new SoC is added?
> 
I understand the concern here.
Will remove this API in next version.
>> +
>> +static inline bool is_video_context_bank_device(struct device *dev)
>> +{
>> +	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
>> +}
>> +
>> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
>> +{
>> +	struct msm_vidc_resource *res = NULL;
> No need to initialize, you use it right after defining.
Agree, will remove.
> 
>> +	int rc = 0;
> I think 'ret' is more common for a return-value-holding variable.
> 
Agree, will replace 'rc' with 'ret' in all APIs in next version
>> +
>> +	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
>> +	if (!res) {
>> +		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
>> +		return -ENOMEM;
>> +	}
>> +	core->resource = res;
> I don't think the 'res' variable makes sense.
> 
Sure, Will update, res->resource
>> +
>> +	rc = call_res_op(core, init, core);
>> +	if (rc) {
>> +		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
>> +		return rc;
> you can omit this line and return rc/ret at the last line of this func.
> 
The abstraction layer for resource is not required so this API will be
changed in next version, will take care of return values as well.
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id msm_vidc_dt_match[] = {
>> +	{.compatible = "qcom,sm8550-vidc"},
> { .compatible = .... " },
> 
>> +	{.compatible = "qcom,vidc,cb-ns"},
>> +	MSM_VIDC_EMPTY_BRACE
> why?
> 
Right, it's not needed, Will replace with {}
>> +};
>> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
>> +
>> +static void msm_vidc_release_video_device(struct video_device *vdev)
>> +{
>> +	d_vpr_e("%s: video device released\n", __func__);
>> +}
> Doesn't sound too useful? And definitely not with an error print?
> 
The device structure is embedded in the core structure, so driver needs to
set the release() callback. hence this API is required.
This API doesn't free anything here because the core struture will be freed
when device is removed.
Will remove error print in next version.
>> +
>> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
>> +					     enum msm_vidc_domain_type type)
>> +{
>> +	int index;
>> +
>> +	if (type == MSM_VIDC_DECODER)
> I'm not sure this is defined.
> 
>> +		index = 0;
>> +	else if (type == MSM_VIDC_ENCODER)
> Or this.
> 
These macros are defined in [1]

[1]:
https://patchwork.linuxtv.org/project/linux-media/patch/1690550624-14642-18-git-send-email-quic_vgarodia@quicinc.com/

> Can't we just assign index = MSM_VIDC_EN/DECODER?
> these are bitmasks hence can not be used as array index and the bitmask
values are being used in driver at multiple places.
>> +		index = 1;
>> +	else
>> +		return;
>> +
>> +	v4l2_m2m_release(core->vdev[index].m2m_dev);
>> +
>> +	video_set_drvdata(&core->vdev[index].vdev, NULL);
>> +	video_unregister_device(&core->vdev[index].vdev);
>> +}
>> +
>> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
>> +					  enum msm_vidc_domain_type type, int nr)
>> +{
>> +	int rc = 0;
>> +	int index;
>> +
>> +	d_vpr_h("%s: domain %d\n", __func__, type);
>> +
>> +	if (type == MSM_VIDC_DECODER)
>> +		index = 0;
>> +	else if (type == MSM_VIDC_ENCODER)
>> +		index = 1;
>> +	else
>> +		return -EINVAL;
>> +
>> +	core->vdev[index].vdev.release =
>> +		msm_vidc_release_video_device;
>> +	core->vdev[index].vdev.fops = core->v4l2_file_ops;
>> +	if (type == MSM_VIDC_DECODER)
>> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
>> +	else
>> +		core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
>> +	core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
>> +	core->vdev[index].type = type;
>> +	core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
>> +	core->vdev[index].vdev.device_caps = core->capabilities[DEVICE_CAPS].value;
>> +	rc = video_register_device(&core->vdev[index].vdev,
>> +				   VFL_TYPE_VIDEO, nr);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register the video device\n");
>> +		return rc;
>> +	}
>> +	video_set_drvdata(&core->vdev[index].vdev, core);
>> +
>> +	core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
>> +	if (IS_ERR(core->vdev[index].m2m_dev)) {
>> +		d_vpr_e("Failed to initialize V4L2 M2M device\n");
>> +		rc = PTR_ERR(core->vdev[index].m2m_dev);
>> +		goto m2m_init_failed;
>> +	}
>> +
>> +	return 0;
>> +
>> +m2m_init_failed:
>> +	video_unregister_device(&core->vdev[index].vdev);
>> +	return rc;
>> +}
>> +
>> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
>> +{
>> +	int rc = 0;
>> +
>> +	if (!core) {
> Are we expecting to ever hit this?
> 
True, it's highly unlikely that we hit this, will remove the check.
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_destroy(&core->lock);
>> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> Not defined.
> 
it is defined in [2]

>> +
>> +	if (core->batch_workq)
>> +		destroy_workqueue(core->batch_workq);
>> +
>> +	if (core->pm_workq)
>> +		destroy_workqueue(core->pm_workq);
>> +
>> +	core->batch_workq = NULL;
>> +	core->pm_workq = NULL;
>> +
>> +	return rc;
>> +}
>> +
>> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
>> +{
>> +	int rc = 0;
>> +
>> +	msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> Not defined.
> 
it is defined in [2]

[2]:
https://patchwork.linuxtv.org/project/linux-media/patch/1690550624-14642-15-git-send-email-quic_vgarodia@quicinc.com/
>> +
>> +	core->pm_workq = create_singlethread_workqueue("pm_workq");
>> +	if (!core->pm_workq) {
>> +		d_vpr_e("%s: create pm workq failed\n", __func__);
>> +		rc = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	core->batch_workq = create_singlethread_workqueue("batch_workq");
>> +	if (!core->batch_workq) {
>> +		d_vpr_e("%s: create batch workq failed\n", __func__);
>> +		rc = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
>> +	core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
>> +	if (!core->packet) {
>> +		d_vpr_e("%s: failed to alloc core packet\n", __func__);
>> +		rc = -ENOMEM;
>> +		goto exit;
>> +	}
>> +
>> +	core->response_packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL);
>> +	if (!core->packet) {
>> +		d_vpr_e("%s: failed to alloc core response packet\n", __func__);
>> +		rc = -ENOMEM;
>> +		goto exit;
>> +	}
>> +
>> +	mutex_init(&core->lock);
>> +	INIT_LIST_HEAD(&core->instances);
>> +	INIT_LIST_HEAD(&core->dangling_instances);
>> +
>> +	INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
>> +	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
>> +
>> +	return 0;
> Either return rc/ret here or don't initialize it at definition.
> 
Sure, Will fix it.
>> +exit:
>> +	if (core->batch_workq)
>> +		destroy_workqueue(core->batch_workq);
>> +	if (core->pm_workq)
>> +		destroy_workqueue(core->pm_workq);
>> +	core->batch_workq = NULL;
>> +	core->pm_workq = NULL;
>> +
>> +	return rc;
>> +}
> [...]
> 
>> +
>> +static int msm_vidc_pm_suspend(struct device *dev)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_core *core;
>> +	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
>> +
>> +	/*
>> +	 * Bail out if
>> +	 * - driver possibly not probed yet
> Would the pm callbacks be registered by then?
> 
>> +	 * - not the main device. We don't support power management on
>> +	 *   subdevices (e.g. context banks)
> I'm not sure registering context banks as different kinds of devices
> within the same driver is a good idea, this seems rather convoluted.
> 
Sure, will remove the separate probe for context bank in next version.
>> +	 */
>> +	if (!dev || !dev->driver || !is_video_device(dev))
>> +		return 0;
>> +
>> +	core = dev_get_drvdata(dev);
>> +	if (!core) {
>> +		d_vpr_e("%s: invalid core\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	core_lock(core, __func__);
>> +	allow = msm_vidc_allow_pm_suspend(core);
>> +
>> +	if (allow == MSM_VIDC_IGNORE) {
>> +		d_vpr_h("%s: pm already suspended\n", __func__);
>> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +		rc = 0;
>> +		goto unlock;
>> +	} else if (allow != MSM_VIDC_ALLOW) {
>> +		d_vpr_h("%s: pm suspend not allowed\n", __func__);
>> +		rc = 0;
>> +		goto unlock;
>> +	}
>> +
>> +	rc = msm_vidc_suspend(core);
>> +	if (rc == -EOPNOTSUPP)
>> +		rc = 0;
>> +	else if (rc)
>> +		d_vpr_e("Failed to suspend: %d\n", rc);
>> +	else
>> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +
>> +unlock:
>> +	core_unlock(core, __func__);
>> +	return rc;
>> +}
>> +
>> +static int msm_vidc_pm_resume(struct device *dev)
> Same comments as in _suspend
> 
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-31 21:23   ` Krzysztof Kozlowski
@ 2023-08-14 18:51     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:51 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 8/1/2023 2:53 AM, Krzysztof Kozlowski wrote:
> On 28/07/2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the platform driver methods, file
>> operations and v4l2 registration.
> 
> 
>> +
>> +	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
>> +	if (!core->debugfs_parent)
>> +		d_vpr_h("Failed to create debugfs for msm_vidc\n");
>> +
>> +	rc = msm_vidc_devm_init_core(&pdev->dev, core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
>> +		goto init_core_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_platform(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
>> +		rc = -EINVAL;
>> +		goto init_plat_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_resources(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
>> +		goto init_res_failed;
> 
> NAK.
> 
> return dev_err_probe.
Sure, will update in next version.
> 
>> +	}
>> +
>> +	rc = msm_vidc_init_core_caps(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
>> +		goto init_res_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_instance_caps(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
>> +		goto init_inst_caps_fail;
>> +	}
>> +
>> +	core->debugfs_root = msm_vidc_debugfs_init_core(core);
>> +	if (!core->debugfs_root)
>> +		d_vpr_h("Failed to init debugfs core\n");
>> +
>> +	d_vpr_h("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.
>> +	 */
>> +	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
>> +				  &pdev->dev);
>> +	if (rc) {
>> +		d_vpr_e("Failed to trigger probe for sub-devices\n");
>> +		goto sub_dev_failed;
>> +	}
>> +
>> +	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register v4l2 device\n");
>> +		goto v4l2_reg_failed;
>> +	}
>> +
>> +	/* setup the decoder device */
>> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register video decoder\n");
>> +		goto dec_reg_failed;
>> +	}
>> +
>> +	/* setup the encoder device */
>> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register video encoder\n");
>> +		goto enc_reg_failed;
>> +	}
>> +
>> +	rc = venus_hfi_queue_init(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: interface queues init failed\n", __func__);
>> +		goto queues_init_failed;
>> +	}
>> +
>> +	rc = msm_vidc_core_init(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: sys init failed\n", __func__);
>> +		goto core_init_failed;
>> +	}
>> +
>> +	d_vpr_h("%s(): succssful\n", __func__);
> 
> No need, drop.
Sure, will drop.
> 
>> +
>> +	return rc;
>> +
>> +core_init_failed:
>> +	venus_hfi_queue_deinit(core);
>> +queues_init_failed:
>> +	of_platform_depopulate(&pdev->dev);
>> +sub_dev_failed:
>> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>> +enc_reg_failed:
>> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>> +dec_reg_failed:
>> +	v4l2_device_unregister(&core->v4l2_dev);
>> +v4l2_reg_failed:
>> +init_inst_caps_fail:
>> +init_res_failed:
>> +init_plat_failed:
>> +init_core_failed:
> 
> Ykes! No. This code needs more work.
> 
I understand, will improve the design in next version.
> Best regards,
> Krzysztof
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-31 21:16   ` Krzysztof Kozlowski
@ 2023-08-14 18:54     ` Dikshita Agarwal
  2023-08-14 20:04       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:54 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 8/1/2023 2:46 AM, Krzysztof Kozlowski wrote:
> On 28/07/2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the platform driver methods, file
>> operations and v4l2 registration.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660 +++++++++++++++++++++
>>  1 file changed, 660 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>> new file mode 100644
>> index 0000000..43439cb
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>> @@ -0,0 +1,660 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iommu.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/stringify.h>
>> +#include <linux/version.h>
>> +#include <linux/workqueue.h>
>> +
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_memory.h"
>> +#include "msm_vidc_platform.h"
>> +#include "msm_vidc_state.h"
>> +#include "venus_hfi.h"
>> +
>> +#define BASE_DEVICE_NUMBER 32
>> +
>> +struct msm_vidc_core *g_core;
>> +
>> +static inline bool is_video_device(struct device *dev)
>> +{
>> +	return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
> 
> Where is it documented? Are you 100% sure that checkpatch does not complain?
We ran the checkpatch on this series with DT binding hence no issues were
reported.
DT binding was missed in this version and will be part of next version.
> 
> I is also a bit surprising to see of_device_is_compatible inside the
> code in some random place. How does it scale? Any driver data and
> variant checks should be done via helpers and driver data, not putting
> compatibles in multiple places.
> 
I understand the concern here, this API will be removed in next version.
> 
>> +}
>> +
>> +static inline bool is_video_context_bank_device(struct device *dev)
>> +{
>> +	return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
>> +}
>> +
>> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
>> +{
>> +	struct msm_vidc_resource *res = NULL;
>> +	int rc = 0;
>> +
>> +	res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
>> +	if (!res) {
>> +		d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
>> +		return -ENOMEM;
>> +	}
>> +	core->resource = res;
>> +
>> +	rc = call_res_op(core, init, core);
>> +	if (rc) {
>> +		d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id msm_vidc_dt_match[] = {
>> +	{.compatible = "qcom,sm8550-vidc"},
>> +	{.compatible = "qcom,vidc,cb-ns"},
> 
> No, srsly, where did you document it?
> 
> If this is not suitable for upstreaming (as it looks like) mark it as
> RFC, so we will know it that you did not run checkpatch...
> 
> 
>> +	MSM_VIDC_EMPTY_BRACE
>> +};
>> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
>> +
>> +static void msm_vidc_release_video_device(struct video_device *vdev)
>> +{
>> +	d_vpr_e("%s: video device released\n", __func__);
> 
> And why would you ever print anything here? What's wrong with tracing?
> 
Sure, I understand having the debug msg here doesn't help, will remove it
in next version.
>> +}
> 
> ...
> 
>> +
>> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_core *core = NULL;
>> +	int nr = BASE_DEVICE_NUMBER;
>> +
>> +	d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
> 
> No debug prints reinventing tracing.
> 
Sure, all custom debug wrappers will be removed in next series.
>> +
>> +	core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL);
>> +	if (!core) {
>> +		d_vpr_e("%s: failed to alloc memory for core\n", __func__);
> 
> Ooops, this for sure did not pass any checks by tools. Sorry, please run
> basic checks like coccinelle, smatch, sparse, W=1 builds.
> 
we ran check patch and smatch on this code but no errors were reported.
please elaborate what issue you see with above code?
>> +		return -ENOMEM;
>> +	}
>> +	g_core = core;
>> +
>> +	core->pdev = pdev;
>> +	dev_set_drvdata(&pdev->dev, core);
>> +
>> +	core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
>> +	if (!core->debugfs_parent)
>> +		d_vpr_h("Failed to create debugfs for msm_vidc\n");
>> +
>> +	rc = msm_vidc_devm_init_core(&pdev->dev, core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init core failed with %d\n", __func__, rc);
>> +		goto init_core_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_platform(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
>> +		rc = -EINVAL;
>> +		goto init_plat_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_resources(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
>> +		goto init_res_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_core_caps(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
>> +		goto init_res_failed;
>> +	}
>> +
>> +	rc = msm_vidc_init_instance_caps(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
>> +		goto init_inst_caps_fail;
>> +	}
>> +
>> +	core->debugfs_root = msm_vidc_debugfs_init_core(core);
>> +	if (!core->debugfs_root)
>> +		d_vpr_h("Failed to init debugfs core\n");
>> +
>> +	d_vpr_h("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.
>> +	 */
>> +	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
>> +				  &pdev->dev);
>> +	if (rc) {
>> +		d_vpr_e("Failed to trigger probe for sub-devices\n");
>> +		goto sub_dev_failed;
>> +	}
>> +
>> +	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register v4l2 device\n");
>> +		goto v4l2_reg_failed;
>> +	}
>> +
>> +	/* setup the decoder device */
>> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register video decoder\n");
>> +		goto dec_reg_failed;
>> +	}
>> +
>> +	/* setup the encoder device */
>> +	rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
>> +	if (rc) {
>> +		d_vpr_e("Failed to register video encoder\n");
>> +		goto enc_reg_failed;
>> +	}
>> +
>> +	rc = venus_hfi_queue_init(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: interface queues init failed\n", __func__);
>> +		goto queues_init_failed;
>> +	}
>> +
>> +	rc = msm_vidc_core_init(core);
>> +	if (rc) {
>> +		d_vpr_e("%s: sys init failed\n", __func__);
>> +		goto core_init_failed;
>> +	}
>> +
>> +	d_vpr_h("%s(): succssful\n", __func__);
>> +
>> +	return rc;
>> +
>> +core_init_failed:
>> +	venus_hfi_queue_deinit(core);
>> +queues_init_failed:
>> +	of_platform_depopulate(&pdev->dev);
>> +sub_dev_failed:
>> +	msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>> +enc_reg_failed:
>> +	msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>> +dec_reg_failed:
>> +	v4l2_device_unregister(&core->v4l2_dev);
>> +v4l2_reg_failed:
>> +init_inst_caps_fail:
>> +init_res_failed:
>> +init_plat_failed:
>> +init_core_failed:
>> +	dev_set_drvdata(&pdev->dev, NULL);
>> +	g_core = NULL;
>> +
>> +	return rc;
>> +}
>> +
>> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
>> +{
>> +	struct msm_vidc_core *core = NULL;
>> +	int rc = 0;
>> +
>> +	if (!pdev) {
>> +		d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
>> +		return -EINVAL;
>> +	} else if (!pdev->dev.parent) {
>> +		d_vpr_e("%s: Failed to find a parent for %s\n",
>> +			__func__, dev_name(&pdev->dev));
>> +		return -ENODEV;
>> +	}
>> +
>> +	d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
>> +
>> +	core = dev_get_drvdata(pdev->dev.parent);
>> +	if (!core) {
>> +		d_vpr_e("%s: core not found in device %s",
>> +			__func__, dev_name(pdev->dev.parent));
>> +		return -EINVAL;
>> +	}
>> +
>> +	rc = msm_vidc_setup_context_bank(core, &pdev->dev);
>> +	if (rc) {
>> +		d_vpr_e("%s: Failed to probe context bank %s\n",
>> +			__func__, dev_name(&pdev->dev));
>> +		return rc;
>> +	}
>> +
>> +	return rc;
>> +}
>> +
>> +static int msm_vidc_probe(struct platform_device *pdev)
>> +{
>> +	if (!pdev) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/*
>> +	 * 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 (is_video_device(&pdev->dev))
>> +		return msm_vidc_probe_video_device(pdev);
>> +	else if (is_video_context_bank_device(&pdev->dev))
>> +		return msm_vidc_probe_context_bank(pdev);
>> +
>> +	/* How did we end up here? */
>> +	WARN_ON(1);
>> +	return -EINVAL;
>> +}
>> +
>> +static int msm_vidc_pm_suspend(struct device *dev)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_core *core;
>> +	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
>> +
>> +	/*
>> +	 * Bail out if
>> +	 * - driver possibly not probed yet
>> +	 * - not the main device. We don't support power management on
>> +	 *   subdevices (e.g. context banks)
>> +	 */
>> +	if (!dev || !dev->driver || !is_video_device(dev))
>> +		return 0;
>> +
>> +	core = dev_get_drvdata(dev);
>> +	if (!core) {
>> +		d_vpr_e("%s: invalid core\n", __func__);
> 
> How core can be invalid?
> 
Agree! core can't be NULL here as driver data won't be invalid if device
still exist.
will remove this NULL check.
>> +		return -EINVAL;
>> +	}
>> +
>> +	core_lock(core, __func__);
> 
> What's this? Why do you use some custom locking (it's almost never a
> good idea)?
> 
Sure, will remove these custom wrapper for locks and use standard
mutex_lock/unlock APIs directly.
>> +	allow = msm_vidc_allow_pm_suspend(core);
>> +
>> +	if (allow == MSM_VIDC_IGNORE) {
>> +		d_vpr_h("%s: pm already suspended\n", __func__);
> 
> So you have bug in PM runtime code? Runtime PM does not suspend devices
> twice.
>core is power collapsed in case of idle state when there is no processing
happening by hardware, this can also change the core state to power_disable.
this check is ensuring if the core is already in power disable state due to
that, then no need to suspend it again.

>> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +		rc = 0;
>> +		goto unlock;
>> +	} else if (allow != MSM_VIDC_ALLOW) {
>> +		d_vpr_h("%s: pm suspend not allowed\n", __func__);
>> +		rc = 0;
>> +		goto unlock;
>> +	}
>> +
>> +	rc = msm_vidc_suspend(core);
>> +	if (rc == -EOPNOTSUPP)
>> +		rc = 0;
>> +	else if (rc)
>> +		d_vpr_e("Failed to suspend: %d\n", rc);
>> +	else
>> +		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +
>> +unlock:
>> +	core_unlock(core, __func__);
>> +	return rc;
>> +}
>> +
> 
> Best regards,
> Krzysztof
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-07-28 13:49   ` Dmitry Baryshkov
@ 2023-08-14 18:58     ` Dikshita Agarwal
  2023-08-14 21:03       ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:58 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 7:19 PM, Dmitry Baryshkov wrote:
> On 28/07/2023 16:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the platform driver methods, file
>> operations and v4l2 registration.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660
>> +++++++++++++++++++++
>>   1 file changed, 660 insertions(+)
>>   create mode 100644
>> drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>> b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>> new file mode 100644
>> index 0000000..43439cb
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>> @@ -0,0 +1,660 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iommu.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/stringify.h>
>> +#include <linux/version.h>
>> +#include <linux/workqueue.h>
>> +
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_memory.h"
>> +#include "msm_vidc_platform.h"
>> +#include "msm_vidc_state.h"
>> +#include "venus_hfi.h"
> 
> This files are not present yet, so this commit doesn't have a change of
> being compiled in any way.
> 
>> +
>> +#define BASE_DEVICE_NUMBER 32
>> +
>> +struct msm_vidc_core *g_core;
>> +
>> +static inline bool is_video_device(struct device *dev)
>> +{
>> +    return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
> 
> Are you going to add future platforms to this list? Please don't duplicate
> of_match_data here.
> Sure, Will remove this API in next version.
>> +}
>> +
>> +static inline bool is_video_context_bank_device(struct device *dev)
>> +{
>> +    return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
>> +}
>> +
>> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
>> +{
>> +    struct msm_vidc_resource *res = NULL;
>> +    int rc = 0;
>> +
>> +    res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
>> +    if (!res) {
>> +        d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
> 
> Where is this macro defined? Please structure your comments in a logical
> way, so that one can read them from the beginning and understand what is
> going one.
> 
> This is not to mention that adding such debugging wrappers doesn't have a
> lot of value.
> 
I understand the concern here, will remove the custom debug wrappers in
next version.
>> +        return -ENOMEM;
>> +    }
>> +    core->resource = res;
>> +
>> +    rc = call_res_op(core, init, core);
> 
> What is call_res_op?
> 
This implements the resource ops, but as we don't need the abstraction for
resource ops, this will be removed in next version.
>> +    if (rc) {
>> +        d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
>> +        return rc;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct of_device_id msm_vidc_dt_match[] = {
>> +    {.compatible = "qcom,sm8550-vidc"},
>> +    {.compatible = "qcom,vidc,cb-ns"},
>> +    MSM_VIDC_EMPTY_BRACE
> 
> NO!!! Please use {} directly.
> 
I Understand, will replace with {}.
>> +};
>> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
>> +
>> +static void msm_vidc_release_video_device(struct video_device *vdev)
>> +{
>> +    d_vpr_e("%s: video device released\n", __func__);
>> +}
>> +
>> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
>> +                         enum msm_vidc_domain_type type)
>> +{
>> +    int index;
>> +
>> +    if (type == MSM_VIDC_DECODER)
>> +        index = 0;
>> +    else if (type == MSM_VIDC_ENCODER)
>> +        index = 1;
>> +    else
>> +        return;
> 
> You can index by the type instead of converting to index.
> 
MSM_VIDC_DECODER/MSM_VIDC_ENCODER are bit masks hence can not be used as
array index and these bit mask values are being used in driver at multiple
places.
>> +
>> +    v4l2_m2m_release(core->vdev[index].m2m_dev);
>> +
>> +    video_set_drvdata(&core->vdev[index].vdev, NULL);
>> +    video_unregister_device(&core->vdev[index].vdev);
>> +}
>> +
>> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
>> +                      enum msm_vidc_domain_type type, int nr)
>> +{
>> +    int rc = 0;
>> +    int index;
>> +
>> +    d_vpr_h("%s: domain %d\n", __func__, type);
>> +
>> +    if (type == MSM_VIDC_DECODER)
>> +        index = 0;
>> +    else if (type == MSM_VIDC_ENCODER)
>> +        index = 1;
>> +    else
>> +        return -EINVAL;
>> +
>> +    core->vdev[index].vdev.release =
>> +        msm_vidc_release_video_device;
>> +    core->vdev[index].vdev.fops = core->v4l2_file_ops;
>> +    if (type == MSM_VIDC_DECODER)
>> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
>> +    else
>> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
>> +    core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
>> +    core->vdev[index].type = type;
>> +    core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
>> +    core->vdev[index].vdev.device_caps =
>> core->capabilities[DEVICE_CAPS].value;
>> +    rc = video_register_device(&core->vdev[index].vdev,
>> +                   VFL_TYPE_VIDEO, nr);
>> +    if (rc) {
>> +        d_vpr_e("Failed to register the video device\n");
>> +        return rc;
>> +    }
>> +    video_set_drvdata(&core->vdev[index].vdev, core);
>> +
>> +    core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
>> +    if (IS_ERR(core->vdev[index].m2m_dev)) {
>> +        d_vpr_e("Failed to initialize V4L2 M2M device\n");
>> +        rc = PTR_ERR(core->vdev[index].m2m_dev);
>> +        goto m2m_init_failed;
>> +    }
>> +
>> +    return 0;
>> +
>> +m2m_init_failed:
>> +    video_unregister_device(&core->vdev[index].vdev);
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
>> +{
>> +    int rc = 0;
>> +
>> +    if (!core) {
>> +        d_vpr_e("%s: invalid params\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    mutex_destroy(&core->lock);
>> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
>> +
>> +    if (core->batch_workq)
>> +        destroy_workqueue(core->batch_workq);
>> +
>> +    if (core->pm_workq)
>> +        destroy_workqueue(core->pm_workq);
>> +
>> +    core->batch_workq = NULL;
>> +    core->pm_workq = NULL;
>> +
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
>> +{
>> +    int rc = 0;
>> +
>> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
>> +
>> +    core->pm_workq = create_singlethread_workqueue("pm_workq");
>> +    if (!core->pm_workq) {
>> +        d_vpr_e("%s: create pm workq failed\n", __func__);
>> +        rc = -EINVAL;
>> +        goto exit;
>> +    }
>> +
>> +    core->batch_workq = create_singlethread_workqueue("batch_workq");
>> +    if (!core->batch_workq) {
>> +        d_vpr_e("%s: create batch workq failed\n", __func__);
>> +        rc = -EINVAL;
>> +        goto exit;
>> +    }
>> +
>> +    core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
>> +    core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size,
>> GFP_KERNEL);
>> +    if (!core->packet) {
>> +        d_vpr_e("%s: failed to alloc core packet\n", __func__);
>> +        rc = -ENOMEM;
>> +        goto exit;
>> +    }
>> +
>> +    core->response_packet = devm_kzalloc(&core->pdev->dev,
>> core->packet_size, GFP_KERNEL);
>> +    if (!core->packet) {
>> +        d_vpr_e("%s: failed to alloc core response packet\n", __func__);
>> +        rc = -ENOMEM;
>> +        goto exit;
>> +    }
>> +
>> +    mutex_init(&core->lock);
>> +    INIT_LIST_HEAD(&core->instances);
>> +    INIT_LIST_HEAD(&core->dangling_instances);
>> +
>> +    INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
>> +    INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
>> +
>> +    return 0;
>> +exit:
>> +    if (core->batch_workq)
>> +        destroy_workqueue(core->batch_workq);
>> +    if (core->pm_workq)
>> +        destroy_workqueue(core->pm_workq);
>> +    core->batch_workq = NULL;
>> +    core->pm_workq = NULL;
>> +
>> +    return rc;
>> +}
>> +
>> +static void msm_vidc_devm_deinit_core(void *res)
>> +{
>> +    struct msm_vidc_core *core = res;
>> +
>> +    msm_vidc_deinitialize_core(core);
>> +}
>> +
>> +static int msm_vidc_devm_init_core(struct device *dev, struct
>> msm_vidc_core *core)
>> +{
>> +    int rc = 0;
>> +
>> +    if (!dev || !core) {
>> +        d_vpr_e("%s: invalid params\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    rc = msm_vidc_initialize_core(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init failed with %d\n", __func__, rc);
>> +        return rc;
>> +    }
>> +
>> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void
>> *)core);
>> +    if (rc)
>> +        return -EINVAL;
>> +
>> +    return rc;
>> +}
>> +
>> +static void msm_vidc_devm_debugfs_put(void *res)
>> +{
>> +    struct dentry *parent = res;
>> +
>> +    debugfs_remove_recursive(parent);
>> +}
>> +
>> +static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev)
> 
> Why is it called get?
> 
this will be removed in next version as part of debug wrappers removal
> 
>> +{
>> +    struct dentry *parent = NULL;
>> +    int rc = 0;
>> +
>> +    if (!dev) {
>> +        d_vpr_e("%s: invalid params\n", __func__);
>> +        return NULL;
>> +    }
>> +
>> +    parent = msm_vidc_debugfs_init_drv();
>> +    if (!parent)
>> +        return NULL;
>> +
>> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void
>> *)parent);
>> +    if (rc)
>> +        return NULL;
>> +
>> +    return parent;
>> +}
>> +
>> +static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
>> +                       struct device *dev)
>> +{
>> +    struct context_bank_info *cb = NULL;
>> +    int rc = 0;
>> +
>> +    cb = msm_vidc_get_context_bank_for_device(core, dev);
>> +    if (!cb) {
>> +        d_vpr_e("%s: Failed to get context bank device for %s\n",
>> +            __func__, dev_name(dev));
>> +        return -EIO;
>> +    }
>> +
>> +    /* populate dev & domain field */
>> +    cb->dev = dev;
>> +    cb->domain = iommu_get_domain_for_dev(cb->dev);
>> +    if (!cb->domain) {
>> +        d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__,
>> dev_name(dev));
>> +        return -EIO;
>> +    }
>> +
>> +    if (cb->dma_mask) {
>> +        rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask);
>> +        if (rc) {
>> +            d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__);
>> +            return rc;
>> +        }
>> +    }
>> +
>> +    /*
>> +     * configure device segment size and segment boundary to ensure
>> +     * iommu mapping returns one mapping (which is required for partial
>> +     * cache operations)
>> +     */
>> +    if (!dev->dma_parms)
>> +        dev->dma_parms =
>> +            devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
>> +    dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
>> +    dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
>> +
>> +    iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler,
>> (void *)core);
>> +
>> +    d_vpr_h("%s: name %s addr start %x size %x secure %d\n",
>> +        __func__, cb->name, cb->addr_range.start,
>> +        cb->addr_range.size, cb->secure);
>> +    d_vpr_h("%s: dma_coherant %d region %d dev_name %s domain %pK
>> dma_mask %llu\n",
>> +        __func__, cb->dma_coherant, cb->region, dev_name(cb->dev),
>> +        cb->domain, cb->dma_mask);
>> +
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_remove_video_device(struct platform_device *pdev)
>> +{
>> +    struct msm_vidc_core *core;
>> +
>> +    if (!pdev) {
>> +        d_vpr_e("%s: invalid input %pK", __func__, pdev);
>> +        return -EINVAL;
>> +    }
>> +
>> +    core = dev_get_drvdata(&pdev->dev);
>> +    if (!core) {
>> +        d_vpr_e("%s: invalid core\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    msm_vidc_core_deinit(core, true);
>> +    venus_hfi_queue_deinit(core);
>> +
>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>> +
>> +    v4l2_device_unregister(&core->v4l2_dev);
>> +
>> +    d_vpr_h("depopulating sub devices\n");
>> +    /*
>> +     * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx
>> +     * When msm_vidc_remove is called for each sub-device, destroy
>> +     * context-bank mappings.
>> +     */
>> +    of_platform_depopulate(&pdev->dev);
>> +
>> +    dev_set_drvdata(&pdev->dev, NULL);
>> +    g_core = NULL;
>> +    d_vpr_h("%s(): succssful\n", __func__);
>> +
>> +    return 0;
>> +}
>> +
>> +static int msm_vidc_remove_context_bank(struct platform_device *pdev)
>> +{
>> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
>> +
>> +    return 0;
>> +}
>> +
>> +static int msm_vidc_remove(struct platform_device *pdev)
>> +{
>> +    /*
>> +     * Sub devices remove will be triggered by of_platform_depopulate()
>> +     * after core_deinit(). It return immediately after completing
>> +     * sub-device remove.
>> +     */
>> +    if (is_video_device(&pdev->dev))
>> +        return msm_vidc_remove_video_device(pdev);
>> +    else if (is_video_context_bank_device(&pdev->dev))
>> +        return msm_vidc_remove_context_bank(pdev);
>> +
>> +    /* How did we end up here? */
>> +    WARN_ON(1);
>> +    return -EINVAL;
>> +}
>> +
>> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
>> +{
>> +    int rc = 0;
>> +    struct msm_vidc_core *core = NULL;
>> +    int nr = BASE_DEVICE_NUMBER;
>> +
>> +    d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
>> +
>> +    core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core),
>> GFP_KERNEL);
>> +    if (!core) {
>> +        d_vpr_e("%s: failed to alloc memory for core\n", __func__);
>> +        return -ENOMEM;
>> +    }
>> +    g_core = core;
>> +
>> +    core->pdev = pdev;
>> +    dev_set_drvdata(&pdev->dev, core);
>> +
>> +    core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
>> +    if (!core->debugfs_parent)
>> +        d_vpr_h("Failed to create debugfs for msm_vidc\n");
>> +
>> +    rc = msm_vidc_devm_init_core(&pdev->dev, core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init core failed with %d\n", __func__, rc);
>> +        goto init_core_failed;
>> +    }
>> +
>> +    rc = msm_vidc_init_platform(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
>> +        rc = -EINVAL;
>> +        goto init_plat_failed;
>> +    }
>> +
>> +    rc = msm_vidc_init_resources(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
>> +        goto init_res_failed;
>> +    }
>> +
>> +    rc = msm_vidc_init_core_caps(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
>> +        goto init_res_failed;
>> +    }
>> +
>> +    rc = msm_vidc_init_instance_caps(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
>> +        goto init_inst_caps_fail;
>> +    }
>> +
>> +    core->debugfs_root = msm_vidc_debugfs_init_core(core);
>> +    if (!core->debugfs_root)
>> +        d_vpr_h("Failed to init debugfs core\n");
>> +
>> +    d_vpr_h("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.
>> +     */
>> +    rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
>> +                  &pdev->dev);
>> +    if (rc) {
>> +        d_vpr_e("Failed to trigger probe for sub-devices\n");
>> +        goto sub_dev_failed;
>> +    }
>> +
>> +    rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
>> +    if (rc) {
>> +        d_vpr_e("Failed to register v4l2 device\n");
>> +        goto v4l2_reg_failed;
>> +    }
>> +
>> +    /* setup the decoder device */
>> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
>> +    if (rc) {
>> +        d_vpr_e("Failed to register video decoder\n");
>> +        goto dec_reg_failed;
>> +    }
>> +
>> +    /* setup the encoder device */
>> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
>> +    if (rc) {
>> +        d_vpr_e("Failed to register video encoder\n");
>> +        goto enc_reg_failed;
>> +    }
>> +
>> +    rc = venus_hfi_queue_init(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: interface queues init failed\n", __func__);
>> +        goto queues_init_failed;
>> +    }
>> +
>> +    rc = msm_vidc_core_init(core);
>> +    if (rc) {
>> +        d_vpr_e("%s: sys init failed\n", __func__);
>> +        goto core_init_failed;
>> +    }
>> +
>> +    d_vpr_h("%s(): succssful\n", __func__);
>> +
>> +    return rc;
>> +
>> +core_init_failed:
>> +    venus_hfi_queue_deinit(core);
>> +queues_init_failed:
>> +    of_platform_depopulate(&pdev->dev);
>> +sub_dev_failed:
>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>> +enc_reg_failed:
>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>> +dec_reg_failed:
>> +    v4l2_device_unregister(&core->v4l2_dev);
>> +v4l2_reg_failed:
>> +init_inst_caps_fail:
>> +init_res_failed:
>> +init_plat_failed:
>> +init_core_failed:
>> +    dev_set_drvdata(&pdev->dev, NULL);
>> +    g_core = NULL;
>> +
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
>> +{
>> +    struct msm_vidc_core *core = NULL;
>> +    int rc = 0;
>> +
>> +    if (!pdev) {
>> +        d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
>> +        return -EINVAL;
>> +    } else if (!pdev->dev.parent) {
>> +        d_vpr_e("%s: Failed to find a parent for %s\n",
>> +            __func__, dev_name(&pdev->dev));
>> +        return -ENODEV;
>> +    }
>> +
>> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
>> +
>> +    core = dev_get_drvdata(pdev->dev.parent);
>> +    if (!core) {
>> +        d_vpr_e("%s: core not found in device %s",
>> +            __func__, dev_name(pdev->dev.parent));
>> +        return -EINVAL;
>> +    }
>> +
>> +    rc = msm_vidc_setup_context_bank(core, &pdev->dev);
>> +    if (rc) {
>> +        d_vpr_e("%s: Failed to probe context bank %s\n",
>> +            __func__, dev_name(&pdev->dev));
>> +        return rc;
>> +    }
>> +
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_probe(struct platform_device *pdev)
>> +{
>> +    if (!pdev) {
>> +        d_vpr_e("%s: invalid params\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    /*
>> +     * 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 (is_video_device(&pdev->dev))
>> +        return msm_vidc_probe_video_device(pdev);
>> +    else if (is_video_context_bank_device(&pdev->dev))
>> +        return msm_vidc_probe_context_bank(pdev);
>> +
>> +    /* How did we end up here? */
>> +    WARN_ON(1);
>> +    return -EINVAL;
> 
> No. Please don't hack around the driver infrastructure and register two
> separate drivers. They can even come in two separate commits, simplifying
> the review.
> 
Sure, will remove the separate probe for context bank in next version.
>> +}
>> +
>> +static int msm_vidc_pm_suspend(struct device *dev)
>> +{
>> +    int rc = 0;
>> +    struct msm_vidc_core *core;
>> +    enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
>> +
>> +    /*
>> +     * Bail out if
>> +     * - driver possibly not probed yet
>> +     * - not the main device. We don't support power management on
>> +     *   subdevices (e.g. context banks)
>> +     */
>> +    if (!dev || !dev->driver || !is_video_device(dev))
>> +        return 0;
>> +
>> +    core = dev_get_drvdata(dev);
>> +    if (!core) {
>> +        d_vpr_e("%s: invalid core\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    core_lock(core, __func__);
>> +    allow = msm_vidc_allow_pm_suspend(core);
>> +
>> +    if (allow == MSM_VIDC_IGNORE) {
>> +        d_vpr_h("%s: pm already suspended\n", __func__);
>> +        msm_vidc_change_core_sub_state(core, 0,
>> CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +        rc = 0;
>> +        goto unlock;
>> +    } else if (allow != MSM_VIDC_ALLOW) {
>> +        d_vpr_h("%s: pm suspend not allowed\n", __func__);
>> +        rc = 0;
>> +        goto unlock;
>> +    }
>> +
>> +    rc = msm_vidc_suspend(core);
>> +    if (rc == -EOPNOTSUPP)
>> +        rc = 0;
>> +    else if (rc)
>> +        d_vpr_e("Failed to suspend: %d\n", rc);
>> +    else
>> +        msm_vidc_change_core_sub_state(core, 0,
>> CORE_SUBSTATE_PM_SUSPEND, __func__);
>> +
>> +unlock:
>> +    core_unlock(core, __func__);
>> +    return rc;
>> +}
>> +
>> +static int msm_vidc_pm_resume(struct device *dev)
>> +{
>> +    struct msm_vidc_core *core;
>> +
>> +    /*
>> +     * Bail out if
>> +     * - driver possibly not probed yet
>> +     * - not the main device. We don't support power management on
>> +     *   subdevices (e.g. context banks)
>> +     */
>> +    if (!dev || !dev->driver || !is_video_device(dev))
>> +        return 0;
>> +
>> +    core = dev_get_drvdata(dev);
>> +    if (!core) {
>> +        d_vpr_e("%s: invalid core\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    /* remove PM suspend from core sub_state */
>> +    core_lock(core, __func__);
>> +    msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0,
>> __func__);
>> +    core_unlock(core, __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)
> 
> No runtime PM?
runtime PM is not added in this series, but we plan to add it at later
point of time.
> 
>> +};
>> +
>> +struct platform_driver msm_vidc_driver = {
>> +    .probe = msm_vidc_probe,
>> +    .remove = msm_vidc_remove,
>> +    .driver = {
>> +        .name = "msm_vidc_v4l2",
>> +        .of_match_table = msm_vidc_dt_match,
>> +        .pm = &msm_vidc_pm_ops,
>> +    },
>> +};
>> +
>> +module_platform_driver(msm_vidc_driver);
>> +MODULE_LICENSE("GPL");
> 
> Unfortunately, after taking a glance at first two patches, I have to stop.
> It is nearly impossible to review it.
> 
> Please start from the beginning, split the driver according to the logical
> functions, not per-file. Ideally something should be compillable starting
> from one of the first patches, if not the very first one. This would
> guarantee that your patchset is structured logically.
> 
> Please add DT bindings. New driver series should start from the bindings
> anyway.
> 
> Please drop your custom debugging wrappers. Use dev_info, dev_warn, dev_err
> and dev_dbg instead.
> 
> Please drop the custom multi-device-single-driver scheme. If there are
> different kinds of devices, there should be different drivers.
> 
> Please take a look around. If you are pushing your driver for kernel
> inclusion, it should not stand out by the style and by the typical code
> seuqences.

Thanks a lot for all your comments, will take care of these in next version.
> 
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 13:34   ` Dmitry Baryshkov
@ 2023-08-14 18:59     ` Dikshita Agarwal
  2023-08-14 21:19       ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 18:59 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 7:04 PM, Dmitry Baryshkov wrote:
> On 28/07/2023 16:23, Vikash Garodia wrote:
>> Here is the implementation of v4l2 wrapper functions for all
>> v4l2 IOCTLs.
> 
> Please do not describe the patch. "Here is..." , "This patch...", "This
> commit..." is a bad style. Please describe _why_ you are doing this. In
> other words, what is the purpose of adding such wrappers. Please rewrite
> your commit messages describing the reasons, not the patch contents.
> 
Sure, Will add descriptive commit text explaining the need of changes, in
next version.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>>   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953
>> +++++++++++++++++++++
>>   2 files changed, 1030 insertions(+)
>>   create mode 100644
>> drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>>   create mode 100644
>> drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> new file mode 100644
>> index 0000000..3766c9d
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> @@ -0,0 +1,77 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef _MSM_VIDC_V4L2_H_
>> +#define _MSM_VIDC_V4L2_H_
>> +
>> +#include <linux/fs.h>
>> +#include <linux/poll.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-dev.h>
>> +#include <media/v4l2-ioctl.h>
>> +
>> +int msm_v4l2_open(struct file *filp);
>> +int msm_v4l2_close(struct file *filp);
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +              struct v4l2_capability *cap);
>> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
>> +              struct v4l2_fmtdesc *f);
>> +int msm_v4l2_try_fmt(struct file *file, void *fh,
>> +             struct v4l2_format *f);
>> +int msm_v4l2_s_fmt(struct file *file, void *fh,
>> +           struct v4l2_format *f);
>> +int msm_v4l2_g_fmt(struct file *file, void *fh,
>> +           struct v4l2_format *f);
>> +int msm_v4l2_s_selection(struct file *file, void *fh,
>> +             struct v4l2_selection *s);
>> +int msm_v4l2_g_selection(struct file *file, void *fh,
>> +             struct v4l2_selection *s);
>> +int msm_v4l2_s_parm(struct file *file, void *fh,
>> +            struct v4l2_streamparm *a);
>> +int msm_v4l2_g_parm(struct file *file, void *fh,
>> +            struct v4l2_streamparm *a);
>> +int msm_v4l2_reqbufs(struct file *file, void *fh,
>> +             struct v4l2_requestbuffers *b);
>> +int msm_v4l2_querybuf(struct file *file, void *fh,
>> +              struct v4l2_buffer *b);
>> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
>> +             struct v4l2_create_buffers *b);
>> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
>> +             struct v4l2_buffer *b);
>> +int msm_v4l2_qbuf(struct file *file, void *fh,
>> +          struct v4l2_buffer *b);
>> +int msm_v4l2_dqbuf(struct file *file, void *fh,
>> +           struct v4l2_buffer *b);
>> +int msm_v4l2_streamon(struct file *file, void *fh,
>> +              enum v4l2_buf_type i);
>> +int msm_v4l2_streamoff(struct file *file, void *fh,
>> +               enum v4l2_buf_type i);
>> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
>> +                 const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
>> +                   const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
>> +                 struct v4l2_decoder_cmd *enc);
>> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
>> +             struct v4l2_decoder_cmd *dec);
>> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
>> +                 struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
>> +             struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
>> +                 struct v4l2_frmsizeenum *fsize);
>> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
>> +                 struct v4l2_frmivalenum *fival);
>> +int msm_v4l2_queryctrl(struct file *file, void *fh,
>> +               struct v4l2_queryctrl *ctrl);
>> +int msm_v4l2_querymenu(struct file *file, void *fh,
>> +               struct v4l2_querymenu *qmenu);
>> +unsigned int msm_v4l2_poll(struct file *filp,
>> +               struct poll_table_struct *pt);
>> +void msm_v4l2_m2m_device_run(void *priv);
>> +void msm_v4l2_m2m_job_abort(void *priv);
>> +
>> +#endif // _MSM_VIDC_V4L2_H_
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> new file mode 100644
>> index 0000000..6dfb18b
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> @@ -0,0 +1,953 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include "msm_vidc.h"
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_inst.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_v4l2.h"
>> +
>> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
>> +{
>> +    if (!filp || !filp->private_data)
>> +        return NULL;
>> +    return container_of(filp->private_data,
>> +                    struct msm_vidc_inst, fh);
>> +}
>> +
>> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
>> +{
>> +    int poll = 0;
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return POLLERR;
>> +    }
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        poll = POLLERR;
>> +        goto exit;
>> +    }
>> +
>> +    poll = msm_vidc_poll((void *)inst, filp, pt);
>> +    if (poll)
>> +        goto exit;
>> +
>> +exit:
>> +    put_inst(inst);
>> +    return poll;
>> +}
>> +
>> +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 *inst;
>> +
>> +    inst = msm_vidc_open(core, vid_dev->type);
>> +    if (!inst) {
>> +        d_vpr_e("Failed to create instance, type = %d\n",
>> +            vid_dev->type);
>> +        return -ENOMEM;
>> +    }
>> +    filp->private_data = &inst->fh;
>> +    return 0;
>> +}
>> +
>> +int msm_v4l2_close(struct file *filp)
>> +{
>> +    int rc = 0;
>> +    struct msm_vidc_inst *inst;
>> +
>> +    inst = get_vidc_inst(filp, NULL);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    rc = msm_vidc_close(inst);
>> +    filp->private_data = NULL;
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +              struct v4l2_capability *cap)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !cap) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_querycap((void *)inst, cap);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_enum_fmt(struct file *filp, void *fh,
>> +              struct v4l2_fmtdesc *f)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !f) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_enum_fmt((void *)inst, f);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !f) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_s_fmt(struct file *filp, void *fh,
>> +           struct v4l2_format *f)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !f) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_g_fmt(struct file *filp, void *fh,
>> +           struct v4l2_format *f)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !f) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_g_fmt((void *)inst, f);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_s_selection(struct file *filp, void *fh,
>> +             struct v4l2_selection *s)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !s) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_s_selection((void *)inst, s);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_g_selection(struct file *filp, void *fh,
>> +             struct v4l2_selection *s)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !s) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_g_selection((void *)inst, s);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_s_parm(struct file *filp, void *fh,
>> +            struct v4l2_streamparm *a)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !a) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_s_param((void *)inst, a);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_g_parm(struct file *filp, void *fh,
>> +            struct v4l2_streamparm *a)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !a) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_g_param((void *)inst, a);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_reqbufs(struct file *filp, void *fh,
>> +             struct v4l2_requestbuffers *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_querybuf(struct file *filp, void *fh,
>> +              struct v4l2_buffer *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_querybuf((void *)inst, b);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
>> +             struct v4l2_create_buffers *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_create_bufs((void *)inst, b);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
>> +             struct v4l2_buffer *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    struct video_device *vdev = video_devdata(filp);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_qbuf(struct file *filp, void *fh,
>> +          struct v4l2_buffer *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    struct video_device *vdev = video_devdata(filp);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EINVAL;
>> +        goto exit;
>> +    }
>> +
>> +    rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
>> +    if (rc)
>> +        goto exit;
>> +
>> +exit:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_dqbuf(struct file *filp, void *fh,
>> +           struct v4l2_buffer *b)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !b) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    rc = msm_vidc_dqbuf(inst, b);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_streamon(struct file *filp, void *fh,
>> +              enum v4l2_buf_type i)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto exit;
>> +    }
>> +
>> +    rc = msm_vidc_streamon((void *)inst, i);
>> +    if (rc)
>> +        goto exit;
>> +
>> +exit:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_streamoff(struct file *filp, void *fh,
>> +               enum v4l2_buf_type i)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    rc = msm_vidc_streamoff((void *)inst, i);
>> +    if (rc)
>> +        i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
>> +
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
>> +                 const struct v4l2_event_subscription *sub)
>> +{
>> +    struct msm_vidc_inst *inst;
>> +    int rc = 0;
>> +
>> +    inst = container_of(fh, struct msm_vidc_inst, fh);
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !sub) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_subscribe_event((void *)inst, sub);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
>> +                   const struct v4l2_event_subscription *sub)
>> +{
>> +    struct msm_vidc_inst *inst;
>> +    int rc = 0;
>> +
>> +    inst = container_of(fh, struct msm_vidc_inst, fh);
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !sub) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    rc = msm_vidc_unsubscribe_event((void *)inst, sub);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh,
>> +                 struct v4l2_decoder_cmd *dec)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !dec) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
>> +             struct v4l2_decoder_cmd *dec)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    enum msm_vidc_event event;
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    if (!dec) {
>> +        i_vpr_e(inst, "%s: invalid params\n", __func__);
>> +        rc = -EINVAL;
>> +        goto unlock;
>> +    }
>> +    if (dec->cmd != V4L2_DEC_CMD_START &&
>> +        dec->cmd != V4L2_DEC_CMD_STOP) {
>> +        i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
>> +        rc = -EINVAL;
>> +        goto unlock;
>> +    }
>> +    event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START :
>> MSM_VIDC_CMD_STOP);
>> +    rc = inst->event_handle(inst, event, NULL);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh,
>> +                 struct v4l2_encoder_cmd *enc)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !enc) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
>> +             struct v4l2_encoder_cmd *enc)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    enum msm_vidc_event event;
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    if (!enc) {
>> +        i_vpr_e(inst, "%s: invalid params\n", __func__);
>> +        rc = -EINVAL;
>> +        goto unlock;
>> +    }
>> +    if (enc->cmd != V4L2_ENC_CMD_START &&
>> +        enc->cmd != V4L2_ENC_CMD_STOP) {
>> +        i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
>> +        rc = -EINVAL;
>> +        goto unlock;
>> +    }
>> +    event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START :
>> MSM_VIDC_CMD_STOP);
>> +    rc = inst->event_handle(inst, event, NULL);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_enum_framesizes(struct file *filp, void *fh,
>> +                 struct v4l2_frmsizeenum *fsize)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !fsize) {
>> +        d_vpr_e("%s: invalid params: %pK %pK\n",
>> +            __func__, inst, fsize);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_enum_framesizes((void *)inst, fsize);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_enum_frameintervals(struct file *filp, void *fh,
>> +                 struct v4l2_frmivalenum *fival)
>> +
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !fival) {
>> +        d_vpr_e("%s: invalid params: %pK %pK\n",
>> +            __func__, inst, fival);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_enum_frameintervals((void *)inst, fival);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_queryctrl(struct file *filp, void *fh,
>> +               struct v4l2_queryctrl *ctrl)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !ctrl) {
>> +        d_vpr_e("%s: invalid instance\n", __func__);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_query_ctrl((void *)inst, ctrl);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +int msm_v4l2_querymenu(struct file *filp, void *fh,
>> +               struct v4l2_querymenu *qmenu)
>> +{
>> +    struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +    int rc = 0;
>> +
>> +    inst = get_inst_ref(g_core, inst);
>> +    if (!inst || !qmenu) {
>> +        d_vpr_e("%s: invalid params %pK %pK\n",
>> +            __func__, inst, qmenu);
>> +        return -EINVAL;
>> +    }
>> +
>> +    client_lock(inst, __func__);
>> +    inst_lock(inst, __func__);
>> +    if (is_session_error(inst)) {
>> +        i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +        rc = -EBUSY;
>> +        goto unlock;
>> +    }
>> +    rc = msm_vidc_query_menu((void *)inst, qmenu);
>> +    if (rc)
>> +        goto unlock;
>> +
>> +unlock:
>> +    inst_unlock(inst, __func__);
>> +    client_unlock(inst, __func__);
>> +    put_inst(inst);
>> +
>> +    return rc;
>> +}
>> +
>> +void msm_v4l2_m2m_device_run(void *priv)
>> +{
>> +    d_vpr_l("%s(): device_run\n", __func__);
>> +}
>> +
>> +void msm_v4l2_m2m_job_abort(void *priv)
>> +{
>> +    struct msm_vidc_inst *inst = priv;
>> +
>> +    if (!inst) {
>> +        d_vpr_e("%s: invalid params\n", __func__);
>> +        return;
>> +    }
>> +    i_vpr_h(inst, "%s: m2m job aborted\n", __func__);
>> +    v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
>> +}
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-31 21:23   ` Krzysztof Kozlowski
@ 2023-08-14 19:00     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:00 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 8/1/2023 2:53 AM, Krzysztof Kozlowski wrote:
> On 28/07/2023 15:23, Vikash Garodia wrote:
>> Here is the implementation of v4l2 wrapper functions for all
>> v4l2 IOCTLs.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>>  .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>>  2 files changed, 1030 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> new file mode 100644
>> index 0000000..3766c9d
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> @@ -0,0 +1,77 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef _MSM_VIDC_V4L2_H_
>> +#define _MSM_VIDC_V4L2_H_
>> +
>> +#include <linux/fs.h>
>> +#include <linux/poll.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-dev.h>
>> +#include <media/v4l2-ioctl.h>
>> +
>> +int msm_v4l2_open(struct file *filp);
>> +int msm_v4l2_close(struct file *filp);
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +		      struct v4l2_capability *cap);
>> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
>> +		      struct v4l2_fmtdesc *f);
>> +int msm_v4l2_try_fmt(struct file *file, void *fh,
>> +		     struct v4l2_format *f);
>> +int msm_v4l2_s_fmt(struct file *file, void *fh,
>> +		   struct v4l2_format *f);
>> +int msm_v4l2_g_fmt(struct file *file, void *fh,
>> +		   struct v4l2_format *f);
>> +int msm_v4l2_s_selection(struct file *file, void *fh,
>> +			 struct v4l2_selection *s);
>> +int msm_v4l2_g_selection(struct file *file, void *fh,
>> +			 struct v4l2_selection *s);
>> +int msm_v4l2_s_parm(struct file *file, void *fh,
>> +		    struct v4l2_streamparm *a);
>> +int msm_v4l2_g_parm(struct file *file, void *fh,
>> +		    struct v4l2_streamparm *a);
>> +int msm_v4l2_reqbufs(struct file *file, void *fh,
>> +		     struct v4l2_requestbuffers *b);
>> +int msm_v4l2_querybuf(struct file *file, void *fh,
>> +		      struct v4l2_buffer *b);
>> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
>> +			 struct v4l2_create_buffers *b);
>> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
>> +			 struct v4l2_buffer *b);
>> +int msm_v4l2_qbuf(struct file *file, void *fh,
>> +		  struct v4l2_buffer *b);
>> +int msm_v4l2_dqbuf(struct file *file, void *fh,
>> +		   struct v4l2_buffer *b);
>> +int msm_v4l2_streamon(struct file *file, void *fh,
>> +		      enum v4l2_buf_type i);
>> +int msm_v4l2_streamoff(struct file *file, void *fh,
>> +		       enum v4l2_buf_type i);
>> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
>> +			     const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
>> +			       const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
>> +			     struct v4l2_decoder_cmd *enc);
>> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
>> +			 struct v4l2_decoder_cmd *dec);
>> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
>> +			     struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
>> +			 struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
>> +			     struct v4l2_frmsizeenum *fsize);
>> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
>> +				 struct v4l2_frmivalenum *fival);
>> +int msm_v4l2_queryctrl(struct file *file, void *fh,
>> +		       struct v4l2_queryctrl *ctrl);
>> +int msm_v4l2_querymenu(struct file *file, void *fh,
>> +		       struct v4l2_querymenu *qmenu);
>> +unsigned int msm_v4l2_poll(struct file *filp,
>> +			   struct poll_table_struct *pt);
>> +void msm_v4l2_m2m_device_run(void *priv);
>> +void msm_v4l2_m2m_job_abort(void *priv);
>> +
>> +#endif // _MSM_VIDC_V4L2_H_
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> new file mode 100644
>> index 0000000..6dfb18b
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> @@ -0,0 +1,953 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include "msm_vidc.h"
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_inst.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_v4l2.h"
>> +
>> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
>> +{
>> +	if (!filp || !filp->private_data)
>> +		return NULL;
>> +	return container_of(filp->private_data,
>> +					struct msm_vidc_inst, fh);
>> +}
>> +
>> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
>> +{
>> +	int poll = 0;
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
> 
> This does not look like Linux coding style. Don't create your own
> abstraction layer over Linux internal API. Use standard Linux functions
> which will behave better and scale along with kernel development.
> 
I understand. these custom debug wrappers will be removed in next version.
>> +		return POLLERR;
>> +	}
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
> 
> i_vpr_e is so obvious for every kernel developer... Please, no.
> 
>> +		poll = POLLERR;
>> +		goto exit;
>> +	}
>> +
>> +	poll = msm_vidc_poll((void *)inst, filp, pt);
>> +	if (poll)
>> +		goto exit;
>> +
>> +exit:
>> +	put_inst(inst);
>> +	return poll;
>> +}
>> +
>> +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 *inst;
>> +
>> +	inst = msm_vidc_open(core, vid_dev->type);
>> +	if (!inst) {
>> +		d_vpr_e("Failed to create instance, type = %d\n",
>> +			vid_dev->type);
>> +		return -ENOMEM;
>> +	}
>> +	filp->private_data = &inst->fh;
>> +	return 0;
>> +}
>> +
>> +int msm_v4l2_close(struct file *filp)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_inst *inst;
>> +
>> +	inst = get_vidc_inst(filp, NULL);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	rc = msm_vidc_close(inst);
>> +	filp->private_data = NULL;
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +		      struct v4l2_capability *cap)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !cap) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
> 
> ? So we don't know what's this? Mutex? Spinlock? Own reinvented lock?
> 
>> +	inst_lock(inst, __func__);
> 
> Neither this?
> 
> No, don't create your own abstractions over standard API.
Sure, will remove these custom wrappers and use standard API directly in
next version.
> 
> Best regards,
> Krzysztof
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 05/33] iris: vidc: add vb2 ops
  2023-07-28 18:03   ` Nicolas Dufresne
@ 2023-08-14 19:03     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:03 UTC (permalink / raw)
  To: Nicolas Dufresne, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 11:33 PM, Nicolas Dufresne wrote:
> Le vendredi 28 juillet 2023 à 18:53 +0530, Vikash Garodia a écrit :
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements vb2 ops for streaming modes for
>> alloc, free, map and unmap buffers.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/inc/msm_vidc_vb2.h     |  39 ++
>>  .../platform/qcom/iris/vidc/src/msm_vidc_vb2.c     | 605 +++++++++++++++++++++
>>  2 files changed, 644 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>> new file mode 100644
>> index 0000000..12378ce
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_vb2.h
>> @@ -0,0 +1,39 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef _MSM_VIDC_VB2_H_
>> +#define _MSM_VIDC_VB2_H_
>> +
>> +#include <media/videobuf2-core.h>
>> +#include <media/videobuf2-v4l2.h>
>> +
>> +#include "msm_vidc_inst.h"
>> +
>> +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
>> +				    u32 type, const char *func);
>> +
>> +/* vb2_mem_ops */
>> +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
>> +		    unsigned long size);
>> +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
>> +			    struct dma_buf *dbuf, unsigned long size);
>> +
>> +void msm_vb2_put(void *buf_priv);
>> +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma);
>> +void msm_vb2_detach_dmabuf(void *buf_priv);
>> +int msm_vb2_map_dmabuf(void *buf_priv);
>> +void msm_vb2_unmap_dmabuf(void *buf_priv);
>> +
>> +/* vb2_ops */
>> +int msm_vb2_queue_setup(struct vb2_queue *q,
>> +			unsigned int *num_buffers, unsigned int *num_planes,
>> +			unsigned int sizes[], struct device *alloc_devs[]);
>> +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
>> +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
>> +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count);
>> +void msm_vb2_stop_streaming(struct vb2_queue *q);
>> +void msm_vb2_buf_queue(struct vb2_buffer *vb2);
>> +#endif // _MSM_VIDC_VB2_H_
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
>> new file mode 100644
>> index 0000000..c936d95
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_vb2.c
>> @@ -0,0 +1,605 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include "msm_vdec.h"
>> +#include "msm_venc.h"
>> +#include "msm_vidc_control.h"
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_inst.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_platform.h"
>> +#include "msm_vidc_power.h"
>> +#include "msm_vidc_vb2.h"
>> +
>> +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst,
>> +				    u32 type, const char *func)
>> +{
>> +	struct vb2_queue *q = NULL;
>> +
>> +	if (type == INPUT_MPLANE) {
>> +		q = inst->bufq[INPUT_PORT].vb2q;
>> +	} else if (type == OUTPUT_MPLANE) {
>> +		q = inst->bufq[OUTPUT_PORT].vb2q;
>> +	} else {
>> +		i_vpr_e(inst, "%s: invalid buffer type %d\n",
>> +			__func__, type);
>> +	}
>> +	return q;
>> +}
>> +
>> +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
>> +		    unsigned long size)
>> +{
>> +	return (void *)0xdeadbeef;
>> +}
>> +
>> +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
>> +			    struct dma_buf *dbuf, unsigned long size)
>> +{
>> +	struct msm_vidc_inst *inst;
>> +	struct msm_vidc_core *core;
>> +	struct msm_vidc_buffer *buf = NULL;
>> +	struct msm_vidc_buffer *ro_buf, *dummy;
>> +
>> +	if (!vb || !dev || !dbuf || !vb->vb2_queue) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return NULL;
>> +	}
>> +	inst = vb->vb2_queue->drv_priv;
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
>> +		return NULL;
>> +	}
>> +	core = inst->core;
>> +
>> +	buf = msm_vidc_fetch_buffer(inst, vb);
>> +	if (!buf) {
>> +		i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__);
>> +		buf = NULL;
>> +		goto exit;
>> +	}
>> +	buf->inst = inst;
>> +	buf->dmabuf = dbuf;
>> +
>> +	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
>> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
>> +			if (ro_buf->dmabuf != buf->dmabuf)
>> +				continue;
>> +			print_vidc_buffer(VIDC_LOW, "low ", "attach: found ro buf", inst, ro_buf);
>> +			buf->attach = ro_buf->attach;
>> +			ro_buf->attach = NULL;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	buf->attach = call_mem_op(core, dma_buf_attach, core, dbuf, dev);
>> +	if (!buf->attach) {
>> +		buf->attach = NULL;
>> +		buf = NULL;
>> +		goto exit;
>> +	}
>> +	print_vidc_buffer(VIDC_LOW, "low ", "attach", inst, buf);
>> +
>> +exit:
>> +	if (!buf)
>> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
>> +	put_inst(inst);
>> +	return buf;
>> +}
>> +
>> +void msm_vb2_put(void *buf_priv)
>> +{
>> +}
>> +
>> +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
>> +{
>> +	return 0;
>> +}
>> +
>> +void msm_vb2_detach_dmabuf(void *buf_priv)
>> +{
>> +	struct msm_vidc_buffer *vbuf = buf_priv;
>> +	struct msm_vidc_buffer *ro_buf, *dummy;
>> +	struct msm_vidc_core *core;
>> +	struct msm_vidc_inst *inst;
>> +
>> +	if (!vbuf || !vbuf->inst) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +	inst = vbuf->inst;
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
>> +		return;
>> +	}
>> +	core = inst->core;
>> +
>> +	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
>> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
>> +			if (ro_buf->dmabuf != vbuf->dmabuf)
>> +				continue;
>> +			print_vidc_buffer(VIDC_LOW, "low ", "detach: found ro buf", inst, ro_buf);
>> +			ro_buf->attach = vbuf->attach;
>> +			vbuf->attach = NULL;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	print_vidc_buffer(VIDC_LOW, "low ", "detach", inst, vbuf);
>> +	if (vbuf->attach && vbuf->dmabuf) {
>> +		call_mem_op(core, dma_buf_detach, core, vbuf->dmabuf, vbuf->attach);
>> +		vbuf->attach = NULL;
>> +	}
>> +
>> +exit:
>> +	vbuf->dmabuf = NULL;
>> +	vbuf->inst = NULL;
>> +}
>> +
>> +int msm_vb2_map_dmabuf(void *buf_priv)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_buffer *buf = buf_priv;
>> +	struct msm_vidc_core *core;
>> +	struct msm_vidc_inst *inst;
>> +	struct msm_vidc_buffer *ro_buf, *dummy;
>> +
>> +	if (!buf || !buf->inst) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +	inst = buf->inst;
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +	core = inst->core;
>> +
>> +	if (is_decode_session(inst) && is_output_buffer(buf->type)) {
>> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
>> +			if (ro_buf->dmabuf != buf->dmabuf)
>> +				continue;
>> +			print_vidc_buffer(VIDC_LOW, "low ", "map: found ro buf", inst, ro_buf);
>> +			buf->sg_table = ro_buf->sg_table;
>> +			buf->device_addr = ro_buf->device_addr;
>> +			ro_buf->sg_table = NULL;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	buf->sg_table = call_mem_op(core, dma_buf_map_attachment, core, buf->attach);
>> +	if (!buf->sg_table || !buf->sg_table->sgl) {
>> +		buf->sg_table = NULL;
>> +		rc = -ENOMEM;
>> +		goto exit;
>> +	}
>> +	buf->device_addr = sg_dma_address(buf->sg_table->sgl);
>> +	print_vidc_buffer(VIDC_HIGH, "high", "map", inst, buf);
>> +
>> +exit:
>> +	if (rc)
>> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
>> +	put_inst(inst);
>> +	return rc;
>> +}
>> +
>> +void msm_vb2_unmap_dmabuf(void *buf_priv)
>> +{
>> +	struct msm_vidc_buffer *vbuf = buf_priv;
>> +	struct msm_vidc_buffer *ro_buf, *dummy;
>> +	struct msm_vidc_core *core;
>> +	struct msm_vidc_inst *inst;
>> +
>> +	if (!vbuf || !vbuf->inst) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +	inst = vbuf->inst;
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
>> +		return;
>> +	}
>> +	core = inst->core;
>> +
>> +	if (is_decode_session(inst) && is_output_buffer(vbuf->type)) {
>> +		list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
>> +			if (ro_buf->dmabuf != vbuf->dmabuf)
>> +				continue;
>> +			print_vidc_buffer(VIDC_LOW, "low ", "unmap: found ro buf", inst, ro_buf);
>> +			ro_buf->sg_table = vbuf->sg_table;
>> +			vbuf->sg_table = NULL;
>> +			vbuf->device_addr = 0x0;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	print_vidc_buffer(VIDC_HIGH, "high", "unmap", inst, vbuf);
>> +	if (vbuf->attach && vbuf->sg_table) {
>> +		call_mem_op(core, dma_buf_unmap_attachment, core, vbuf->attach, vbuf->sg_table);
>> +		vbuf->sg_table = NULL;
>> +		vbuf->device_addr = 0x0;
>> +	}
>> +
>> +exit:
>> +	return;
>> +}
>> +
>> +int msm_vb2_queue_setup(struct vb2_queue *q,
>> +			unsigned int *num_buffers, unsigned int *num_planes,
>> +			unsigned int sizes[], struct device *alloc_devs[])
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_inst *inst;
>> +	struct msm_vidc_core *core;
>> +	int port;
>> +	struct v4l2_format *f;
>> +	enum msm_vidc_buffer_type buffer_type = 0;
>> +	enum msm_vidc_buffer_region region = MSM_VIDC_REGION_NONE;
>> +	struct context_bank_info *cb = NULL;
>> +	struct msm_vidc_buffers *buffers;
>> +
>> +	if (!q || !num_buffers || !num_planes ||
>> +	    !sizes || !q->drv_priv) {
>> +		d_vpr_e("%s: invalid params, q = %pK, %pK, %pK\n",
>> +			__func__, q, num_buffers, num_planes);
>> +		return -EINVAL;
>> +	}
>> +	inst = q->drv_priv;
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params %pK\n", __func__, inst);
>> +		return -EINVAL;
>> +	}
>> +	core = inst->core;
>> +
>> +	if (is_state(inst, MSM_VIDC_STREAMING)) {
>> +		i_vpr_e(inst, "%s: invalid state %d\n", __func__, inst->state);
>> +		return -EINVAL;
>> +	}
>> +
>> +	port = v4l2_type_to_driver_port(inst, q->type, __func__);
>> +	if (port < 0)
>> +		return -EINVAL;
>> +
>> +	/* prepare dependency list once per session */
>> +	if (!inst->caps_list_prepared) {
>> +		rc = msm_vidc_prepare_dependency_list(inst);
>> +		if (rc)
>> +			return rc;
>> +		inst->caps_list_prepared = true;
>> +	}
>> +
>> +	/* adjust v4l2 properties for master port */
>> +	if ((is_encode_session(inst) && port == OUTPUT_PORT) ||
>> +	    (is_decode_session(inst) && port == INPUT_PORT)) {
>> +		rc = msm_vidc_adjust_v4l2_properties(inst);
>> +		if (rc) {
>> +			i_vpr_e(inst, "%s: failed to adjust properties\n", __func__);
>> +			return rc;
>> +		}
>> +	}
>> +
>> +	if (*num_planes && (port == INPUT_PORT || port == OUTPUT_PORT)) {
>> +		f = &inst->fmts[port];
>> +		if (*num_planes != f->fmt.pix_mp.num_planes) {
>> +			i_vpr_e(inst, "%s: requested num_planes %d not supported %d\n",
>> +				__func__, *num_planes, f->fmt.pix_mp.num_planes);
>> +			return -EINVAL;
>> +		}
>> +		if (sizes[0] < inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage) {
>> +			i_vpr_e(inst, "%s: requested size %d not acceptable\n",
>> +				__func__, sizes[0]);
>> +			return -EINVAL;
>> +		}
>> +	}
>> +
>> +	buffer_type = v4l2_type_to_driver(q->type, __func__);
>> +	if (!buffer_type)
>> +		return -EINVAL;
>> +
>> +	rc = msm_vidc_free_buffers(inst, buffer_type);
>> +	if (rc) {
>> +		i_vpr_e(inst, "%s: failed to free buffers, type %s\n",
>> +			__func__, v4l2_type_name(q->type));
>> +		return rc;
>> +	}
>> +
>> +	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
>> +	if (!buffers)
>> +		return -EINVAL;
>> +
>> +	buffers->min_count = call_session_op(core, min_count, inst, buffer_type);
>> +	buffers->extra_count = call_session_op(core, extra_count, inst, buffer_type);
>> +	if (*num_buffers < buffers->min_count + buffers->extra_count)
>> +		*num_buffers = buffers->min_count + buffers->extra_count;
>> +	buffers->actual_count = *num_buffers;
>> +	*num_planes = 1;
>> +
>> +	buffers->size = call_session_op(core, buffer_size, inst, buffer_type);
>> +
>> +	inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage = buffers->size;
>> +	sizes[0] = inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage;
>> +
>> +	rc = msm_vidc_allocate_buffers(inst, buffer_type, *num_buffers);
>> +	if (rc) {
>> +		i_vpr_e(inst, "%s: failed to allocate buffers, type %s\n",
>> +			__func__, v4l2_type_name(q->type));
>> +		return rc;
>> +	}
>> +
>> +	region = call_mem_op(core, buffer_region, inst, buffer_type);
>> +	cb = msm_vidc_get_context_bank_for_region(core, region);
>> +	if (!cb) {
>> +		d_vpr_e("%s: Failed to get context bank device\n",
>> +			__func__);
>> +		return -EIO;
>> +	}
>> +	q->dev = cb->dev;
>> +
>> +	i_vpr_h(inst,
>> +		"queue_setup: type %s num_buffers %d sizes[0] %d cb %s\n",
>> +		v4l2_type_name(q->type), *num_buffers, sizes[0], cb->name);
>> +	return rc;
>> +}
>> +
>> +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_inst *inst;
>> +
>> +	if (!q || !q->drv_priv) {
>> +		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
>> +		return -EINVAL;
>> +	}
>> +	inst = q->drv_priv;
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q);
>> +	if (rc) {
>> +		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
>> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
>> +		goto exit;
>> +	}
>> +
>> +exit:
>> +	return rc;
>> +}
>> +
>> +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
>> +{
>> +	enum msm_vidc_buffer_type buf_type;
>> +	int rc = 0;
>> +
>> +	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
>> +		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
>> +		return -EINVAL;
>> +	}
>> +	if (!is_decode_session(inst) && !is_encode_session(inst)) {
>> +		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
>> +		return -EINVAL;
>> +	}
>> +	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
>> +
>> +	if (!inst->once_per_session_set) {
> 
> This seems miss-placed, I think you should be able to move this into your driver
> open() call and drop the inst->once_per_session_set boolean>
The APIs being invoked under this condition can't be moved to open.
msm_vidc_session_set_codec is called to set the codec which is not known at
open, and only known at s_fmt.
buffer sizes for different internal buffer will be known only after s_fmt.
hence these setting are being done in start streaming.

Thanks,
Dikshita
>> +		inst->once_per_session_set = true;
>> +		rc = msm_vidc_session_set_codec(inst);
>> +		if (rc)
>> +			return rc;
>> +
>> +		if (is_encode_session(inst)) {
>> +			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
>> +								       MSM_VIDC_BUF_ARP);
>> +			if (rc)
>> +				return rc;
>> +		} else if (is_decode_session(inst)) {
>> +			rc = msm_vidc_session_set_default_header(inst);
>> +			if (rc)
>> +				return rc;
>> +
>> +			rc = msm_vidc_alloc_and_queue_session_int_bufs(inst,
>> +								       MSM_VIDC_BUF_PERSIST);
>> +			if (rc)
>> +				return rc;
>> +		}
>> +	}
>> +
>> +	if (is_decode_session(inst))
>> +		inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
>> +
>> +	msm_vidc_allow_dcvs(inst);
>> +	msm_vidc_power_data_reset(inst);
>> +
>> +	if (q->type == INPUT_MPLANE) {
>> +		if (is_decode_session(inst))
>> +			rc = msm_vdec_streamon_input(inst);
>> +		else if (is_encode_session(inst))
>> +			rc = msm_venc_streamon_input(inst);
>> +	} else if (q->type == OUTPUT_MPLANE) {
>> +		if (is_decode_session(inst))
>> +			rc = msm_vdec_streamon_output(inst);
>> +		else if (is_encode_session(inst))
>> +			rc = msm_venc_streamon_output(inst);
>> +	}
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* print final buffer counts & size details */
>> +	msm_vidc_print_buffer_info(inst);
>> +
>> +	/* print internal buffer memory usage stats */
>> +	msm_vidc_print_memory_stats(inst);
>> +
>> +	buf_type = v4l2_type_to_driver(q->type, __func__);
>> +	if (!buf_type)
>> +		return -EINVAL;
>> +
>> +	/* queue pending buffers */
>> +	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* initialize statistics timer(one time) */
>> +	if (!inst->stats.time_ms)
>> +		inst->stats.time_ms = ktime_get_ns() / 1000 / 1000;
>> +
>> +	/* schedule to print buffer statistics */
>> +	rc = schedule_stats_work(inst);
>> +	if (rc)
>> +		return rc;
>> +
>> +	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
>> +	    (q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
>> +		rc = msm_vidc_get_properties(inst);
>> +		if (rc)
>> +			return rc;
>> +	}
>> +
>> +	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
>> +	return rc;
>> +}
>> +
>> +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
>> +{
>> +	int rc = 0;
>> +
>> +	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
>> +		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
>> +		return -EINVAL;
>> +	}
>> +	if (!is_decode_session(inst) && !is_encode_session(inst)) {
>> +		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
>> +		return -EINVAL;
>> +	}
>> +	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
>> +
>> +	if (q->type == INPUT_MPLANE) {
>> +		if (is_decode_session(inst))
>> +			rc = msm_vdec_streamoff_input(inst);
>> +		else if (is_encode_session(inst))
>> +			rc = msm_venc_streamoff_input(inst);
>> +	} else if (q->type == OUTPUT_MPLANE) {
>> +		if (is_decode_session(inst))
>> +			rc = msm_vdec_streamoff_output(inst);
>> +		else if (is_encode_session(inst))
>> +			rc = msm_venc_streamoff_output(inst);
>> +	}
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* Input port streamoff */
>> +	if (q->type == INPUT_MPLANE) {
>> +		/* flush timestamps list */
>> +		msm_vidc_flush_ts(inst);
>> +	}
>> +
>> +	/* print internal buffer memory usage stats */
>> +	msm_vidc_print_memory_stats(inst);
>> +
>> +	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
>> +	return rc;
>> +}
>> +
>> +void msm_vb2_stop_streaming(struct vb2_queue *q)
>> +{
>> +	struct msm_vidc_inst *inst;
>> +	int rc = 0;
>> +
>> +	if (!q || !q->drv_priv) {
>> +		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
>> +		return;
>> +	}
>> +	inst = q->drv_priv;
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +
>> +	rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q);
>> +	if (rc) {
>> +		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
>> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
>> +	}
>> +}
>> +
>> +void msm_vb2_buf_queue(struct vb2_buffer *vb2)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_inst *inst;
>> +	struct dma_buf *dbuf = NULL;
>> +	struct msm_vidc_core *core;
>> +	u64 ktime_ns = ktime_get_ns();
>> +
>> +	if (!vb2) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +
>> +	inst = vb2_get_drv_priv(vb2->vb2_queue);
>> +	if (!inst || !inst->core) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +	core = inst->core;
>> +
>> +	if (!vb2->planes[0].bytesused) {
>> +		if (vb2->type == INPUT_MPLANE) {
>> +			/* Expecting non-zero filledlen on INPUT port */
>> +			i_vpr_e(inst,
>> +				"%s: zero bytesused input buffer not supported\n", __func__);
>> +			rc = -EINVAL;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	inst->last_qbuf_time_ns = ktime_ns;
>> +
>> +	if (vb2->type == INPUT_MPLANE) {
>> +		rc = msm_vidc_update_input_rate(inst, div_u64(ktime_ns, 1000));
>> +		if (rc)
>> +			goto exit;
>> +	}
>> +
>> +	/*
>> +	 * Userspace may close fd(from other thread), before driver attempts to call
>> +	 * dma_buf_get() in qbuf(FTB) sequence(for decoder output buffer) which may
>> +	 * lead to different kind of security issues. Add check to compare if dma_buf
>> +	 * address is matching with driver dma_buf_get returned address for that fd.
>> +	 */
>> +
>> +	dbuf = call_mem_op(core, dma_buf_get, inst, vb2->planes[0].m.fd);
>> +	if (dbuf != vb2->planes[0].dbuf) {
>> +		i_vpr_e(inst, "%s: invalid dmabuf address 0x%p expected 0x%p\n",
>> +			__func__, dbuf, vb2->planes[0].dbuf);
>> +		rc = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	if (is_decode_session(inst))
>> +		rc = msm_vdec_qbuf(inst, vb2);
>> +	else if (is_encode_session(inst))
>> +		rc = msm_venc_qbuf(inst, vb2);
>> +	else
>> +		rc = -EINVAL;
>> +	if (rc) {
>> +		print_vb2_buffer("failed vb2-qbuf", inst, vb2);
>> +		goto exit;
>> +	}
>> +
>> +exit:
>> +	if (dbuf)
>> +		call_mem_op(core, dma_buf_put, inst, dbuf);
>> +
>> +	if (rc) {
>> +		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
>> +		vb2_buffer_done(vb2, VB2_BUF_STATE_ERROR);
>> +	}
>> +}
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 06/33] iris: vidc: define video core and instance context
  2023-07-28 15:47   ` Bryan O'Donoghue
@ 2023-08-14 19:04     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:04 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vikash Garodia, stanimir.k.varbanov,
	agross, andersson, konrad.dybcio, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm



On 7/28/2023 9:17 PM, Bryan O'Donoghue wrote:
> On 28/07/2023 14:23, Vikash Garodia wrote:
>> +#define call_iris_op(d, op, ...)            \
>> +    (((d) && (d)->iris_ops && (d)->iris_ops->op) ? \
>> +    ((d)->iris_ops->op(__VA_ARGS__)) : 0)
>> +
>> +struct msm_vidc_iris_ops {
>> +    int (*boot_firmware)(struct msm_vidc_core *core);
>> +    int (*raise_interrupt)(struct msm_vidc_core *core);
>> +    int (*clear_interrupt)(struct msm_vidc_core *core);
>> +    int (*prepare_pc)(struct msm_vidc_core *core);
>> +    int (*power_on)(struct msm_vidc_core *core);
>> +    int (*power_off)(struct msm_vidc_core *core);
>> +    int (*watchdog)(struct msm_vidc_core *core, u32 intr_status);
>> +};
> 
> So I don't see how this code supports booting the venus firmware, is that
> not required on 8550 ?
> 
> I've applied the full patchset to -next
> 
> We don't appear to have enumerated callbacks for booting, clearing
> interrupts..

Hi Bryan,

Seems you are looking in the incorrect folder, these APIs are implemented
in variant specific folder, i.e. iris/variant/iris3

Thanks,
Dikshita
> 
> grep -r clear_interrupt drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: call_iris_op(core,
> clear_interrupt, core);
> 
> grep -r boot_firmware drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> call_iris_op(core, boot_firmware, core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> call_iris_op(core, boot_firmware, core);
> 
> There is dead code @ raise_interrupt..
> 
> grep -r raise_interrupt drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:    
> call_iris_op(core, raise_interrupt, core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:        
> //call_iris_op(core, raise_interrupt, core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c:        
> //call_iris_op(core, raise_interrupt, core);
> 
> grep -r clear_interrupt drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c: call_iris_op(core,
> clear_interrupt, core);
> 
> grep -r prepare_pc drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:int
> __prepare_pc(struct msm_vidc_core *core)
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> call_iris_op(core, prepare_pc, core);
> 
> 
> Here we have an admixture of the new name "Iris" with the old name "venus"
> 
> grep -r power_on drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:static int
> __venus_power_on(struct msm_vidc_core *core)
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> call_iris_op(core, power_on, core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> __venus_power_on(core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:        goto
> err_venus_power_on;
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:err_venus_power_on:
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> __venus_power_on(core);
> 
> grep -r power_off drivers/media/platform/qcom/iris/vidc/src/*
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:        goto
> skip_power_off;
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:skip_power_off:
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:static int
> __venus_power_off(struct msm_vidc_core *core)
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:    rc =
> call_iris_op(core, power_off, core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:
> __venus_power_off(core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:
> __venus_power_off(core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:
> __venus_power_off(core);
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:
> __venus_power_off(core);
> 
> Lending credence to the argument we could incorporate all of some of the is
> logic in the existing venus driver.
> 
> ---
> bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-07-28 16:28   ` Bjorn Andersson
  2023-07-28 17:22     ` Konrad Dybcio
@ 2023-08-14 19:05     ` Dikshita Agarwal
  1 sibling, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:05 UTC (permalink / raw)
  To: Bjorn Andersson, Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm



On 7/28/2023 9:58 PM, Bjorn Andersson wrote:
> On Fri, Jul 28, 2023 at 06:53:22PM +0530, Vikash Garodia wrote:
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
> [..]
>> +static const struct msm_vidc_memory_ops msm_mem_ops = {
>> +	.dma_buf_get                    = msm_vidc_dma_buf_get,
>> +	.dma_buf_put                    = msm_vidc_dma_buf_put,
>> +	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
>> +	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
>> +	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
>> +	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
>> +	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
>> +	.memory_alloc_map               = msm_vidc_memory_alloc_map,
>> +	.memory_unmap_free              = msm_vidc_memory_unmap_free,
>> +	.buffer_region                  = msm_vidc_buffer_region,
> 
> Will there ever be more than one implementation of the
> msm_vidc_memory_ops?
> 
> Unless there's a really strong reason, just call the functions directly
> without the function pointers and call_mem_op(), this will be slightly
> faster, but more importantly it allows for much faster navigation of the
> code base.
> 
That's right, implementation of these APIs won't change for different platform.
Will remove the ops and use direct function in next version.

Thanks,
Dikshita
> Regards,
> Bjorn

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-07-28 17:22     ` Konrad Dybcio
@ 2023-08-14 19:06       ` Dikshita Agarwal
  2023-08-25 18:38         ` Konrad Dybcio
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:06 UTC (permalink / raw)
  To: Konrad Dybcio, Bjorn Andersson, Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm



On 7/28/2023 10:52 PM, Konrad Dybcio wrote:
> On 28.07.2023 18:28, Bjorn Andersson wrote:
>> On Fri, Jul 28, 2023 at 06:53:22PM +0530, Vikash Garodia wrote:
>>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
>> [..]
>>> +static const struct msm_vidc_memory_ops msm_mem_ops = {
>>> +	.dma_buf_get                    = msm_vidc_dma_buf_get,
>>> +	.dma_buf_put                    = msm_vidc_dma_buf_put,
>>> +	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
>>> +	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
>>> +	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
>>> +	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
>>> +	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
>>> +	.memory_alloc_map               = msm_vidc_memory_alloc_map,
>>> +	.memory_unmap_free              = msm_vidc_memory_unmap_free,
>>> +	.buffer_region                  = msm_vidc_buffer_region,
>>
>> Will there ever be more than one implementation of the
>> msm_vidc_memory_ops?
>>
>> Unless there's a really strong reason, just call the functions directly
>> without the function pointers and call_mem_op(), this will be slightly
>> faster, but more importantly it allows for much faster navigation of the
>> code base.
> Same for HFI ops
Hi Konrad,
There are no HFI ops in this driver, are you referring to anything else
here, could you please point me to it?
> 
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 12/33] iris: vidc: add helper functions for resource management
  2023-07-28 17:30   ` Konrad Dybcio
@ 2023-08-14 19:07     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:07 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:00 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements ops to initialize, enable and disable extrenal
>> resources needed by video driver like power domains, clocks etc.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> There's a whole bunch of kerneldoc abuses (comments should start with
> /* and not /**). Make sure you have proper spaces between single-line
> C-style comments (e.g. /*Get should be /* Get etc.)
> 
> Capitalizing the first word within the comment would be nice too.
Agree! will fix the comments in next version.
> 
> 
> Do we need a separate bus table? i.e. does it make sense to adjust the
> bandwidth values separately from the clock rates?

Yes, we do need to vote for bus bandwidth separately hence separate bus
table is required.
> 
> Do you think there will be more than one set of msm_vidc_resources_ops?
> Perhaps it'd make sense to drop that layer of abstraction if not. Many
> function names could drop the __ prefix.
> 
> A whole bunch of d_vpr_h seem almost excessive.
Sure, all custom debug wrappers will be removed in next version
> 
> MSM_VIDC_CLKFLAG_* are unused.
> 
Thanks for pointing it, will remove in next version.

Thanks,
Dikshita
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 13/33] iris: vidc: add helper functions for power management
  2023-07-28 17:46   ` Konrad Dybcio
@ 2023-08-14 19:10     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:10 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:16 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> this implements functions for calculating current load of the
>> hardware. Depending on the count of instances and
>> resolutions it selects the best clock rate for the video
>> core. Also it scales clocks, power and enable/disable dcvs.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---[...]
> 
>> +
>> +/* TODO: Move to dtsi OR use source clock instead of branch clock.*/
>> +#define MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO 3
> Seems unused in this patch.
Right, moved to the resource.c file where it is used.
> 
>> +
>> +enum vidc_bus_type {
>> +	PERF,
>> +	DDR,
>> +	LLCC,
>> +};
>> +
>> +/*
>> + * Minimum dimensions for which to calculate bandwidth.
>> + * This means that anything bandwidth(0, 0) ==
>> + * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
>> + */
>> +static const struct {
>> +	int height, width;
>> +} BASELINE_DIMENSIONS = {
>> +	.width = 1280,
>> +	.height = 720,
>> +};
>> +
>> +/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
> if 'b', the multiplier must be 1024 or it makes no sense
>
we are calculating the value in decimal hence multiplication factor is 1000.

>> +#define kbps(__mbps) ((__mbps) * 1000)
>> +#define bps(__mbps) (kbps(__mbps) * 1000)
>> +
> [...]
> 
>> +void __dump(struct dump dump[], int len)
>> +{
>> +	int c = 0;
>> +
>> +	for (c = 0; c < len; ++c) {
>> +		char format_line[128] = "", formatted_line[128] = "";
> That's a lot of bytes on the stack..
> 
This code will be removed in next version as part of custom debug wrapper
removal.
>> +
>> +		if (dump[c].val == DUMP_HEADER_MAGIC) {
>> +			snprintf(formatted_line, sizeof(formatted_line), "%s\n",
>> +				 dump[c].key);
>> +		} else {
>> +			snprintf(format_line, sizeof(format_line),
>> +				 "    %-35s: %s\n", dump[c].key,
>> +					 dump[c].format);
>> +			snprintf(formatted_line, sizeof(formatted_line),
>> +				 format_line, dump[c].val);
>> +		}
>> +		d_vpr_b("%s", formatted_line);
>> +	}
>> +}
>> +
>> +u64 msm_vidc_max_freq(struct msm_vidc_inst *inst)
>> +{
>> +	struct msm_vidc_core *core;
>> +	struct frequency_table *freq_tbl;
>> +	u64 freq = 0;
>> +
>> +	core = inst->core;
>> +
>> +	if (!core->resource || !core->resource->freq_set.freq_tbl ||
>> +	    !core->resource->freq_set.count) {
>> +		i_vpr_e(inst, "%s: invalid frequency table\n", __func__);
>> +		return freq;
>> +	}
>> +	freq_tbl = core->resource->freq_set.freq_tbl;
> Do we need a separate freuqency table if we have OPP?
we are using freq table at multiple places to
- setting freq to turbo
- limiting the freq to NOM
- changing the frequency values based on DCVS
hence this table is need.

will explore more to see if it can be removed.
> [...]
> 
> 
>> +	if (inst->power.fw_cf) {
>> +		cf = inst->power.fw_cf;
>> +		frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2;
> too magic!
> 
this is the standard calculation for calculating the frame size, will try
to simplify this in next version.

Thanks,
Dikshita
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI)
  2023-07-28 15:58   ` Bryan O'Donoghue
@ 2023-08-14 19:11     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:11 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vikash Garodia, stanimir.k.varbanov,
	agross, andersson, konrad.dybcio, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm



On 7/28/2023 9:28 PM, Bryan O'Donoghue wrote:
> On 28/07/2023 14:23, Vikash Garodia wrote:
>> +    rc = hfi_packet_sys_intraframe_powercollapse(core, core->packet,
>> +                             core->packet_size, enable);
>> +    if (rc)
>> +        return rc;
> 
> I'm 99.9999999999 % sure this is misnamed.
> 
> "Inter" means in-between two things.
> "Intra" means inside of one thing.
> 
> So "intraframe" means inside of one frame "interframe" would mean power
> collapsing in-between two frames, which is what I think this does.
> 
> And I'd still rather be adding inter-frame power-collapse to as many
> different versions of the existing silicon and new silicon as opposed to
> segregating it off in a new driver.
> 
> I'm assuming that more than sm8550 supports it since @ the end of the day
> this is a firmware feature to power-collapse during an active session when
> we aren't busy.
> 
You are actually 100% correct here, it is indeed inter frame power collapse,
Will rename this api with hfi_packet_sys_interframe_powercollapse

Thanks,
Dikshita
> ---
> bod

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI)
  2023-07-31  9:02   ` Bryan O'Donoghue
@ 2023-08-14 19:11     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:11 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vikash Garodia, stanimir.k.varbanov,
	agross, andersson, konrad.dybcio, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm



On 7/31/2023 2:32 PM, Bryan O'Donoghue wrote:
> On 28/07/2023 14:23, Vikash Garodia wrote:
>> This implements the interface for communication between
>> host driver and firmware through interface commands and messages.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> 
> More dead code here
> 
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:542:    //if
> (core->last_packet_type != HFI_CMD_SYS_PC_PREP)
> drivers/media/platform/qcom/iris/vidc/src/venus_hfi.c:543:    //
> core->skip_pc_count = 0;
> 
Thanks for pointing it, will remove in next version
> ---
> bod
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 24/33] iris: vidc: add debug files
  2023-07-31 21:31   ` Krzysztof Kozlowski
@ 2023-08-14 19:12     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:12 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 8/1/2023 3:01 AM, Krzysztof Kozlowski wrote:
> On 28/07/2023 15:23, Vikash Garodia wrote:
>> this implements the debugging framework.
> 
> Your commit msgs are not helping to understand why do you need it and
> what is this doing. Based on this commit description I would ask you to
> drop most of this code as it looks useless. Extend the commit msg to
> provide proper justification and list of features each unit provides.
> 
> Please do not use "This commit/patch", but imperative mood. See longer
> explanation here:
> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
> 
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/inc/msm_vidc_debug.h   | 186 +++++++
>>  .../platform/qcom/iris/vidc/src/msm_vidc_debug.c   | 581 +++++++++++++++++++++
>>  2 files changed, 767 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_debug.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>> new file mode 100644
>> index 0000000..ffced01
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_debug.h
>> @@ -0,0 +1,186 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __MSM_VIDC_DEBUG__
>> +#define __MSM_VIDC_DEBUG__
>> +
>> +#include <linux/debugfs.h>
>> +#include <linux/delay.h>
>> +#include <linux/errno.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/types.h>
>> +
>> +struct msm_vidc_core;
>> +struct msm_vidc_inst;
>> +
>> +#ifndef VIDC_DBG_LABEL
>> +#define VIDC_DBG_LABEL "msm_vidc"
>> +#endif
> 
> Drop these three. Don't re-invent Linux kernel API.
> 
>> +
>> +/* Allow only 6 prints/sec */
>> +#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ)
>> +#define VIDC_DBG_SESSION_RATELIMIT_BURST 6
>> +
>> +#define VIDC_DBG_TAG_INST VIDC_DBG_LABEL ": %4s: %s: "
>> +#define VIDC_DBG_TAG_CORE VIDC_DBG_LABEL ": %4s: %08x: %s: "
>> +#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: "
>> +#define DEFAULT_SID ((u32)-1)
>> +
>> +#ifndef MSM_VIDC_EMPTY_BRACE
>> +#define MSM_VIDC_EMPTY_BRACE {},
> 
> That's the funniest code I saw since some time.
> 
>> +#endif
>> +
>> +extern unsigned int msm_vidc_debug;
> 
> Nope.
> 
>> +extern unsigned int msm_fw_debug;
> 
> Nope.
> 
>> +extern bool msm_vidc_fw_dump;
> 
> Nope.
> 
>> +
>> +/* do not modify the log message as it is used in test scripts */
>> +#define FMT_STRING_SET_CTRL \
>> +	"%s: state %s, name %s, id 0x%x value %d\n"
>> +#define FMT_STRING_STATE_CHANGE \
>> +	"%s: state changed to %s from %s\n"
>> +#define FMT_STRING_MSG_SFR \
>> +	"SFR Message from FW: %s\n"
>> +#define FMT_STRING_FAULT_HANDLER \
>> +	"%s: faulting address: %lx\n"
>> +#define FMT_STRING_SET_CAP \
>> +	"set cap: name: %24s, cap value: %#10x, hfi: %#10llx\n"
>> +
>> +/* To enable messages OR these values and
>> + * echo the result to debugfs file.
>> + *
>> + * To enable all messages set msm_vidc_debug = 0x101F
>> + */
>> +
>> +enum vidc_msg_prio_drv {
>> +	VIDC_ERR        = 0x00000001,
>> +	VIDC_HIGH       = 0x00000002,
>> +	VIDC_LOW        = 0x00000004,
>> +	VIDC_PERF       = 0x00000008,
>> +	VIDC_PKT        = 0x00000010,
>> +	VIDC_BUS        = 0x00000020,
>> +	VIDC_STAT       = 0x00000040,
>> +	VIDC_ENCODER    = 0x00000100,
>> +	VIDC_DECODER    = 0x00000200,
>> +	VIDC_PRINTK     = 0x10000000,
>> +	VIDC_FTRACE     = 0x20000000,
>> +};
>> +
>> +enum vidc_msg_prio_fw {
>> +	FW_LOW          = 0x00000001,
>> +	FW_MED          = 0x00000002,
>> +	FW_HIGH         = 0x00000004,
>> +	FW_ERROR        = 0x00000008,
>> +	FW_FATAL        = 0x00000010,
>> +	FW_PERF         = 0x00000020,
>> +	FW_CACHE_LOW    = 0x00000100,
>> +	FW_CACHE_MED    = 0x00000200,
>> +	FW_CACHE_HIGH   = 0x00000400,
>> +	FW_CACHE_ERROR  = 0x00000800,
>> +	FW_CACHE_FATAL  = 0x00001000,
>> +	FW_CACHE_PERF   = 0x00002000,
>> +	FW_PRINTK       = 0x10000000,
>> +	FW_FTRACE       = 0x20000000,
>> +};
>> +
>> +#define DRV_LOG        (VIDC_ERR | VIDC_PRINTK)
>> +#define DRV_LOGSHIFT   (0)
>> +#define DRV_LOGMASK    (0x0FFFFFFF)
>> +
>> +#define FW_LOG         (FW_ERROR | FW_FATAL | FW_PRINTK)
>> +#define FW_LOGSHIFT    (0)
>> +#define FW_LOGMASK     (0x0FFFFFFF)
>> +
>> +#define dprintk_inst(__level, __level_str, inst, __fmt, ...) \
>> +	do { \
>> +		if (inst && (msm_vidc_debug & (__level))) { \
>> +			pr_info(VIDC_DBG_TAG_INST __fmt, \
>> +				__level_str, \
>> +				inst->debug_str, \
>> +				##__VA_ARGS__); \
>> +		} \
>> +	} while (0)
>> +
>> +#define i_vpr_e(inst, __fmt, ...) dprintk_inst(VIDC_ERR,  "err ", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_i(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_h(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_l(inst, __fmt, ...) dprintk_inst(VIDC_LOW,  "low ", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_p(inst, __fmt, ...) dprintk_inst(VIDC_PERF, "perf", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_t(inst, __fmt, ...) dprintk_inst(VIDC_PKT,  "pkt ", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_b(inst, __fmt, ...) dprintk_inst(VIDC_BUS,  "bus ", inst, __fmt, ##__VA_ARGS__)
> 
> NAK for entire interface. Please use standard debugging functions, not
> pr_info for everything.
> 
> dev_dbg, dev_info, dev_warn, dev_err. Only these.
> 
> 
>> +#define i_vpr_s(inst, __fmt, ...) dprintk_inst(VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
>> +
>> +#define i_vpr_hp(inst, __fmt, ...) \
>> +	dprintk_inst(VIDC_HIGH | VIDC_PERF, "high", inst, __fmt, ##__VA_ARGS__)
>> +#define i_vpr_hs(inst, __fmt, ...) \
>> +	dprintk_inst(VIDC_HIGH | VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__)
>> +> +#define dprintk_core(__level, __level_str, __fmt, ...) \
> 
> NAK
> 
>> +	do { \
>> +		if (msm_vidc_debug & (__level)) { \
>> +			pr_info(VIDC_DBG_TAG_CORE __fmt, \
>> +				__level_str, \
>> +				DEFAULT_SID, \
>> +				"codec", \
>> +				##__VA_ARGS__); \
>> +		} \
>> +	} while (0)
>> +
>> +#define d_vpr_e(__fmt, ...) dprintk_core(VIDC_ERR,  "err ", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_h(__fmt, ...) dprintk_core(VIDC_HIGH, "high", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_l(__fmt, ...) dprintk_core(VIDC_LOW,  "low ", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_p(__fmt, ...) dprintk_core(VIDC_PERF, "perf", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_t(__fmt, ...) dprintk_core(VIDC_PKT,  "pkt ", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_b(__fmt, ...) dprintk_core(VIDC_BUS,  "bus ", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_s(__fmt, ...) dprintk_core(VIDC_STAT, "stat", __fmt, ##__VA_ARGS__)
>> +#define d_vpr_hs(__fmt, ...) \
>> +	dprintk_core(VIDC_HIGH | VIDC_STAT, "high", __fmt, ##__VA_ARGS__)
>> +
>> +#define dprintk_ratelimit(__level, __level_str, __fmt, ...) \
>> +	do { \
>> +		if (msm_vidc_check_ratelimit()) { \
>> +			dprintk_core(__level, __level_str, __fmt, ##__VA_ARGS__); \
>> +		} \
>> +	} while (0)
>> +
>> +#define dprintk_firmware(__level, __fmt, ...)	\
>> +	do { \
>> +		if ((msm_fw_debug & (__level)) & FW_PRINTK) { \
>> +			pr_info(FW_DBG_TAG __fmt, \
>> +				"fw", \
>> +				##__VA_ARGS__); \
>> +		} \
>> +	} while (0)
>> +
>> +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,
>> +};
>> +
>> +enum msm_vidc_bug_on_error {
>> +	MSM_VIDC_BUG_ON_FATAL             = BIT(0),
>> +	MSM_VIDC_BUG_ON_NOC               = BIT(1),
>> +	MSM_VIDC_BUG_ON_WD_TIMEOUT        = BIT(2),
>> +};
>> +
>> +struct dentry *msm_vidc_debugfs_init_drv(void);
>> +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core);
>> +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
>> +					  struct dentry *parent);
>> +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
>> +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
>> +			     enum msm_vidc_debugfs_event e);
>> +int msm_vidc_check_ratelimit(void);
>> +
>> +static inline bool is_stats_enabled(void)
>> +{
>> +	return !!(msm_vidc_debug & VIDC_STAT);
> 
> ...
> 
>> +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core)
>> +{
>> +	struct dentry *dir = NULL;
>> +	char debugfs_name[MAX_DEBUGFS_NAME];
>> +	struct dentry *parent;
>> +
>> +	if (!core->debugfs_parent) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		goto failed_create_dir;
>> +	}
>> +	parent = core->debugfs_parent;
>> +
>> +	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core");
>> +	dir = debugfs_create_dir(debugfs_name, parent);
>> +	if (IS_ERR_OR_NULL(dir)) {
>> +		dir = NULL;
>> +		d_vpr_e("Failed to create debugfs for msm_vidc\n");
>> +		goto failed_create_dir;
>> +	}
>> +	if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) {
>> +		d_vpr_e("debugfs_create_file: fail\n");
>> +		goto failed_create_dir;
>> +	}
>> +
>> +	if (!debugfs_create_file("stats_delay_ms", 0644, dir, core, &stats_delay_fops)) {
>> +		d_vpr_e("debugfs_create_file: fail\n");
> 
> 
> What is this entire debugfs supposed to provide?
will remove this whole file in next version as part of custom debug
wrappers removal.

Thanks,
Dikshita
> 
> 
> 
> Best regards,
> Krzysztof
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 08/33] iris: vidc: add video decoder files
  2023-07-28 17:21   ` Konrad Dybcio
@ 2023-08-14 19:13     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:13 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 10:51 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> This implements decoder functionalities of the driver.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> I see a whole bunch of shifts, ANDs, etc.
> 
> Please convert that to GENMASK + FIELD_PREP/FIELD_GET
> 
Sure, will explore more on this.

> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-07-28 17:50   ` Nicolas Dufresne
@ 2023-08-14 19:14     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:14 UTC (permalink / raw)
  To: Nicolas Dufresne, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 11:20 PM, Nicolas Dufresne wrote:
> Le vendredi 28 juillet 2023 à 18:53 +0530, Vikash Garodia a écrit :
>> Here is the implementation of v4l2 wrapper functions for all
>> v4l2 IOCTLs.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
>>  .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953 +++++++++++++++++++++
>>  2 files changed, 1030 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> new file mode 100644
>> index 0000000..3766c9d
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
>> @@ -0,0 +1,77 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef _MSM_VIDC_V4L2_H_
>> +#define _MSM_VIDC_V4L2_H_
>> +
>> +#include <linux/fs.h>
>> +#include <linux/poll.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-dev.h>
>> +#include <media/v4l2-ioctl.h>
>> +
>> +int msm_v4l2_open(struct file *filp);
>> +int msm_v4l2_close(struct file *filp);
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +		      struct v4l2_capability *cap);
>> +int msm_v4l2_enum_fmt(struct file *file, void *fh,
>> +		      struct v4l2_fmtdesc *f);
>> +int msm_v4l2_try_fmt(struct file *file, void *fh,
>> +		     struct v4l2_format *f);
>> +int msm_v4l2_s_fmt(struct file *file, void *fh,
>> +		   struct v4l2_format *f);
>> +int msm_v4l2_g_fmt(struct file *file, void *fh,
>> +		   struct v4l2_format *f);
>> +int msm_v4l2_s_selection(struct file *file, void *fh,
>> +			 struct v4l2_selection *s);
>> +int msm_v4l2_g_selection(struct file *file, void *fh,
>> +			 struct v4l2_selection *s);
>> +int msm_v4l2_s_parm(struct file *file, void *fh,
>> +		    struct v4l2_streamparm *a);
>> +int msm_v4l2_g_parm(struct file *file, void *fh,
>> +		    struct v4l2_streamparm *a);
>> +int msm_v4l2_reqbufs(struct file *file, void *fh,
>> +		     struct v4l2_requestbuffers *b);
>> +int msm_v4l2_querybuf(struct file *file, void *fh,
>> +		      struct v4l2_buffer *b);
>> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
>> +			 struct v4l2_create_buffers *b);
>> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
>> +			 struct v4l2_buffer *b);
>> +int msm_v4l2_qbuf(struct file *file, void *fh,
>> +		  struct v4l2_buffer *b);
>> +int msm_v4l2_dqbuf(struct file *file, void *fh,
>> +		   struct v4l2_buffer *b);
>> +int msm_v4l2_streamon(struct file *file, void *fh,
>> +		      enum v4l2_buf_type i);
>> +int msm_v4l2_streamoff(struct file *file, void *fh,
>> +		       enum v4l2_buf_type i);
>> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
>> +			     const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
>> +			       const struct v4l2_event_subscription *sub);
>> +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh,
>> +			     struct v4l2_decoder_cmd *enc);
>> +int msm_v4l2_decoder_cmd(struct file *file, void *fh,
>> +			 struct v4l2_decoder_cmd *dec);
>> +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh,
>> +			     struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_encoder_cmd(struct file *file, void *fh,
>> +			 struct v4l2_encoder_cmd *enc);
>> +int msm_v4l2_enum_framesizes(struct file *file, void *fh,
>> +			     struct v4l2_frmsizeenum *fsize);
>> +int msm_v4l2_enum_frameintervals(struct file *file, void *fh,
>> +				 struct v4l2_frmivalenum *fival);
>> +int msm_v4l2_queryctrl(struct file *file, void *fh,
>> +		       struct v4l2_queryctrl *ctrl);
>> +int msm_v4l2_querymenu(struct file *file, void *fh,
>> +		       struct v4l2_querymenu *qmenu);
>> +unsigned int msm_v4l2_poll(struct file *filp,
>> +			   struct poll_table_struct *pt);
>> +void msm_v4l2_m2m_device_run(void *priv);
>> +void msm_v4l2_m2m_job_abort(void *priv);
>> +
>> +#endif // _MSM_VIDC_V4L2_H_
>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> new file mode 100644
>> index 0000000..6dfb18b
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c
>> @@ -0,0 +1,953 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include "msm_vidc.h"
>> +#include "msm_vidc_core.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_driver.h"
>> +#include "msm_vidc_inst.h"
>> +#include "msm_vidc_internal.h"
>> +#include "msm_vidc_v4l2.h"
>> +
>> +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
>> +{
>> +	if (!filp || !filp->private_data)
>> +		return NULL;
>> +	return container_of(filp->private_data,
>> +					struct msm_vidc_inst, fh);
>> +}
>> +
>> +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
>> +{
>> +	int poll = 0;
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL);
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return POLLERR;
>> +	}
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		poll = POLLERR;
>> +		goto exit;
>> +	}
>> +
>> +	poll = msm_vidc_poll((void *)inst, filp, pt);
>> +	if (poll)
>> +		goto exit;
>> +
>> +exit:
>> +	put_inst(inst);
>> +	return poll;
>> +}
>> +
>> +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 *inst;
>> +
>> +	inst = msm_vidc_open(core, vid_dev->type);
>> +	if (!inst) {
>> +		d_vpr_e("Failed to create instance, type = %d\n",
>> +			vid_dev->type);
>> +		return -ENOMEM;
>> +	}
>> +	filp->private_data = &inst->fh;
>> +	return 0;
>> +}
>> +
>> +int msm_v4l2_close(struct file *filp)
>> +{
>> +	int rc = 0;
>> +	struct msm_vidc_inst *inst;
>> +
>> +	inst = get_vidc_inst(filp, NULL);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	rc = msm_vidc_close(inst);
>> +	filp->private_data = NULL;
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_querycap(struct file *filp, void *fh,
>> +		      struct v4l2_capability *cap)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !cap) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
> 
> You always takes both locks, which may indicate that you have one too many lock.
> Any reason my the m2m_ctx->q_lock did not work for you ?
> 
m2m_ctx→q_lock takes care of ioctls which modify the queue, client lock is
used to serialize the other ioctls.
inst->lock is to serialize the client thread and hardware response thread.

we recently encountered a bug on venus driver, where during close, an
interrupt from hardware is raised and both APIs are accessing the same
queue memory, since forward and reverse threads are not protected through
any lock, we are seeing raise condition there which will be resolved by
having this inst->lock for the same.

Thanks,
Dikshita
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_querycap((void *)inst, cap);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_enum_fmt(struct file *filp, void *fh,
>> +		      struct v4l2_fmtdesc *f)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !f) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_enum_fmt((void *)inst, f);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !f) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_s_fmt(struct file *filp, void *fh,
>> +		   struct v4l2_format *f)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !f) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_g_fmt(struct file *filp, void *fh,
>> +		   struct v4l2_format *f)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !f) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_g_fmt((void *)inst, f);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_s_selection(struct file *filp, void *fh,
>> +			 struct v4l2_selection *s)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !s) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_s_selection((void *)inst, s);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_g_selection(struct file *filp, void *fh,
>> +			 struct v4l2_selection *s)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !s) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_g_selection((void *)inst, s);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_s_parm(struct file *filp, void *fh,
>> +		    struct v4l2_streamparm *a)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !a) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_s_param((void *)inst, a);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_g_parm(struct file *filp, void *fh,
>> +		    struct v4l2_streamparm *a)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !a) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_g_param((void *)inst, a);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_reqbufs(struct file *filp, void *fh,
>> +		     struct v4l2_requestbuffers *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_querybuf(struct file *filp, void *fh,
>> +		      struct v4l2_buffer *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_querybuf((void *)inst, b);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_create_bufs(struct file *filp, void *fh,
>> +			 struct v4l2_create_buffers *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_create_bufs((void *)inst, b);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_prepare_buf(struct file *filp, void *fh,
>> +			 struct v4l2_buffer *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	struct video_device *vdev = video_devdata(filp);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_qbuf(struct file *filp, void *fh,
>> +		  struct v4l2_buffer *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	struct video_device *vdev = video_devdata(filp);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
>> +	if (rc)
>> +		goto exit;
>> +
>> +exit:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_dqbuf(struct file *filp, void *fh,
>> +		   struct v4l2_buffer *b)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !b) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	rc = msm_vidc_dqbuf(inst, b);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_streamon(struct file *filp, void *fh,
>> +		      enum v4l2_buf_type i)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto exit;
>> +	}
>> +
>> +	rc = msm_vidc_streamon((void *)inst, i);
>> +	if (rc)
>> +		goto exit;
>> +
>> +exit:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_streamoff(struct file *filp, void *fh,
>> +		       enum v4l2_buf_type i)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	rc = msm_vidc_streamoff((void *)inst, i);
>> +	if (rc)
>> +		i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
>> +
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
>> +			     const struct v4l2_event_subscription *sub)
>> +{
>> +	struct msm_vidc_inst *inst;
>> +	int rc = 0;
>> +
>> +	inst = container_of(fh, struct msm_vidc_inst, fh);
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !sub) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_subscribe_event((void *)inst, sub);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
>> +			       const struct v4l2_event_subscription *sub)
>> +{
>> +	struct msm_vidc_inst *inst;
>> +	int rc = 0;
>> +
>> +	inst = container_of(fh, struct msm_vidc_inst, fh);
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !sub) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	rc = msm_vidc_unsubscribe_event((void *)inst, sub);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh,
>> +			     struct v4l2_decoder_cmd *dec)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !dec) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
>> +			 struct v4l2_decoder_cmd *dec)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	enum msm_vidc_event event;
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	if (!dec) {
>> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
>> +		rc = -EINVAL;
>> +		goto unlock;
>> +	}
>> +	if (dec->cmd != V4L2_DEC_CMD_START &&
>> +	    dec->cmd != V4L2_DEC_CMD_STOP) {
>> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
>> +		rc = -EINVAL;
>> +		goto unlock;
>> +	}
>> +	event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
>> +	rc = inst->event_handle(inst, event, NULL);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh,
>> +			     struct v4l2_encoder_cmd *enc)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !enc) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
>> +			 struct v4l2_encoder_cmd *enc)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	enum msm_vidc_event event;
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	if (!enc) {
>> +		i_vpr_e(inst, "%s: invalid params\n", __func__);
>> +		rc = -EINVAL;
>> +		goto unlock;
>> +	}
>> +	if (enc->cmd != V4L2_ENC_CMD_START &&
>> +	    enc->cmd != V4L2_ENC_CMD_STOP) {
>> +		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
>> +		rc = -EINVAL;
>> +		goto unlock;
>> +	}
>> +	event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
>> +	rc = inst->event_handle(inst, event, NULL);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_enum_framesizes(struct file *filp, void *fh,
>> +			     struct v4l2_frmsizeenum *fsize)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !fsize) {
>> +		d_vpr_e("%s: invalid params: %pK %pK\n",
>> +			__func__, inst, fsize);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_enum_framesizes((void *)inst, fsize);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_enum_frameintervals(struct file *filp, void *fh,
>> +				 struct v4l2_frmivalenum *fival)
>> +
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !fival) {
>> +		d_vpr_e("%s: invalid params: %pK %pK\n",
>> +			__func__, inst, fival);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_enum_frameintervals((void *)inst, fival);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_queryctrl(struct file *filp, void *fh,
>> +		       struct v4l2_queryctrl *ctrl)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !ctrl) {
>> +		d_vpr_e("%s: invalid instance\n", __func__);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_query_ctrl((void *)inst, ctrl);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +int msm_v4l2_querymenu(struct file *filp, void *fh,
>> +		       struct v4l2_querymenu *qmenu)
>> +{
>> +	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
>> +	int rc = 0;
>> +
>> +	inst = get_inst_ref(g_core, inst);
>> +	if (!inst || !qmenu) {
>> +		d_vpr_e("%s: invalid params %pK %pK\n",
>> +			__func__, inst, qmenu);
>> +		return -EINVAL;
>> +	}
>> +
>> +	client_lock(inst, __func__);
>> +	inst_lock(inst, __func__);
>> +	if (is_session_error(inst)) {
>> +		i_vpr_e(inst, "%s: inst in error state\n", __func__);
>> +		rc = -EBUSY;
>> +		goto unlock;
>> +	}
>> +	rc = msm_vidc_query_menu((void *)inst, qmenu);
>> +	if (rc)
>> +		goto unlock;
>> +
>> +unlock:
>> +	inst_unlock(inst, __func__);
>> +	client_unlock(inst, __func__);
>> +	put_inst(inst);
>> +
>> +	return rc;
>> +}
>> +
>> +void msm_v4l2_m2m_device_run(void *priv)
>> +{
>> +	d_vpr_l("%s(): device_run\n", __func__);
>> +}
>> +
>> +void msm_v4l2_m2m_job_abort(void *priv)
>> +{
>> +	struct msm_vidc_inst *inst = priv;
>> +
>> +	if (!inst) {
>> +		d_vpr_e("%s: invalid params\n", __func__);
>> +		return;
>> +	}
>> +	i_vpr_h(inst, "%s: m2m job aborted\n", __func__);
>> +	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
>> +}
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 10/33] iris: vidc: add helper functions
  2023-07-28 17:41   ` Konrad Dybcio
@ 2023-08-14 19:15     ` Dikshita Agarwal
  2023-08-16 11:46       ` Konrad Dybcio
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:15 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:11 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> This implements common helper functions for v4l2 to vidc and
>> vice versa conversion for different enums.
>> Add helpers for state checks, buffer management, locks etc.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> [...]
> 
>> +
>> +#define is_odd(val) ((val) % 2 == 1)
>> +#define in_range(val, min, max) (((min) <= (val)) && ((val) <= (max)))
>> +#define COUNT_BITS(a, out) {       \
> hweight.* functions?
> 
> [...]
> 
sure, will replace with hweight.
>> +
>> +const char *cap_name(enum msm_vidc_inst_capability_type cap_id)
>> +{
>> +	const char *name = "UNKNOWN CAP";
> Perhaps it'd be worth to include the unknown cap id here
> 
could you please elaborate more on this.
>> +
>> +	if (cap_id >= ARRAY_SIZE(cap_name_arr))
>> +		goto exit;
>> +
>> +	name = cap_name_arr[cap_id];
>> +
>> +exit:
>> +	return name;
>> +}
> [...]
> 
>> +
>> +const char *buf_name(enum msm_vidc_buffer_type type)
>> +{
>> +	const char *name = "UNKNOWN BUF";
> Similarly here
> 
could you please elaborate more on this.
>> +
>> +	if (type >= ARRAY_SIZE(buf_type_name_arr))
>> +		goto exit;
>> +
>> +	name = buf_type_name_arr[type];
>> +
>> +exit:
>> +	return name;
>> +}
> [...]
> 
>> +const char *v4l2_type_name(u32 port)
>> +{
>> +	switch (port) {
> switch-case seems a bit excessive here.
> 
>> +	case INPUT_MPLANE:      return "INPUT";
>> +	case OUTPUT_MPLANE:     return "OUTPUT";
>> +	}
>> +
>> +	return "UNKNOWN";
>> +}
that's right, will fix in next version
> [...]
> 
> There's some more stuff I'd comment on, but 4500 lines in a single patch
> is way too much to logically follow.
> 
> Couple more style suggestions:
> - use Reverse-Christmas-tree sorting for variable declarations
> - some oneliner functions could possibly become preprocessor macros
> - when printing giant debug messages, you may want to use loops
> - make sure your indentation is in order, 100 chars per line is
>   totally fine
> - generally inline magic hex values are discouraged, but if they're
>   necessary, the hex should be lowercase
Nice suggestions! will take care of these comments in next version.

Thanks,
Dikshita
> 
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 14/33] iris: vidc: add helpers for state management
  2023-07-28 17:52   ` Konrad Dybcio
@ 2023-08-14 19:17     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:17 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:22 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> This implements the functions to handle different core
>> and instance state transitions.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> [...]
> 
>> +enum msm_vidc_core_sub_state {
>> +	CORE_SUBSTATE_NONE                   = 0x0,
>> +	CORE_SUBSTATE_POWER_ENABLE           = BIT(0),
>> +	CORE_SUBSTATE_GDSC_HANDOFF           = BIT(1),
>> +	CORE_SUBSTATE_PM_SUSPEND             = BIT(2),
>> +	CORE_SUBSTATE_FW_PWR_CTRL            = BIT(3),
>> +	CORE_SUBSTATE_PAGE_FAULT             = BIT(4),
>> +	CORE_SUBSTATE_CPU_WATCHDOG           = BIT(5),
>> +	CORE_SUBSTATE_VIDEO_UNRESPONSIVE     = BIT(6),
>> +	CORE_SUBSTATE_MAX                    = BIT(7),
> Why store it in an enum if they're not consecutive? You can make them
> preprocessor #defines.
> 
I understand that these are not consecutive but a enum for these makes them
under one roof which is easy to read and maintain, we will loose this if
replaced with macro.
>> +};
>> +
>> +enum msm_vidc_core_event_type {
>> +	CORE_EVENT_NONE                      = BIT(0),
>> +	CORE_EVENT_UPDATE_SUB_STATE          = BIT(1),
>> +};
> Ditto (even though techinically they're consecutive)
> 
>> +
>> +enum msm_vidc_state {
>> +	MSM_VIDC_OPEN,
>> +	MSM_VIDC_INPUT_STREAMING,
>> +	MSM_VIDC_OUTPUT_STREAMING,
>> +	MSM_VIDC_STREAMING,
>> +	MSM_VIDC_CLOSE,
>> +	MSM_VIDC_ERROR,
>> +};
>> +
>> +#define MSM_VIDC_SUB_STATE_NONE          0
>> +#define MSM_VIDC_MAX_SUB_STATES          6
>> +/*
>> + * max value of inst->sub_state if all
>> + * the 6 valid bits are set i.e 111111==>63
>> + */
>> +#define MSM_VIDC_MAX_SUB_STATE_VALUE     ((1 << MSM_VIDC_MAX_SUB_STATES) - 1)
>> +
>> +enum msm_vidc_sub_state {
>> +	MSM_VIDC_DRAIN                     = BIT(0),
>> +	MSM_VIDC_DRC                       = BIT(1),
>> +	MSM_VIDC_DRAIN_LAST_BUFFER         = BIT(2),
>> +	MSM_VIDC_DRC_LAST_BUFFER           = BIT(3),
>> +	MSM_VIDC_INPUT_PAUSE               = BIT(4),
>> +	MSM_VIDC_OUTPUT_PAUSE              = BIT(5),
> Ditto
> 
these are bit wise and are being used in state machine. At a time, two or
more bits can be set to define the state of and instance, hence needed.

> [...]
> 
>> +static int msm_vidc_core_init_wait_state(struct msm_vidc_core *core,
>> +					 enum msm_vidc_core_event_type type,
>> +					 struct msm_vidc_event_data *data)
>> +{
>> +	int rc = 0;
> rc seems never assigned again, good to drop
> 
> [...]
> 
Sure, will remove in next version
>> +
>> +static int msm_vidc_core_init_state(struct msm_vidc_core *core,
>> +				    enum msm_vidc_core_event_type type,
>> +				    struct msm_vidc_event_data *data)
>> +{
>> +	int rc = 0;
> Ditto
> 
> [...]
> 
>> +static int msm_vidc_core_error_state(struct msm_vidc_core *core,
>> +				     enum msm_vidc_core_event_type type,
>> +				     struct msm_vidc_event_data *data)
>> +{
>> +	int rc = 0;
> Ditto
> 
> [...]
> 
>> +int msm_vidc_update_core_state(struct msm_vidc_core *core,
>> +			       enum msm_vidc_core_state request_state, const char *func)
>> +{
>> +	struct msm_vidc_core_state_handle *state_handle = NULL;
>> +	int rc = 0;
> Ditto
> 
> [...]
> 
>> +int msm_vidc_change_core_state(struct msm_vidc_core *core,
>> +			       enum msm_vidc_core_state request_state, const char *func)
>> +{
>> +	enum msm_vidc_allow allow;
>> +	int rc = 0;
> Ditto
> 
will remove all such instances of unused rc in next version
> [...]
> 
>> +bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state)
>> +{
>> +	return inst->state == state;
>> +}
>> +
>> +bool is_sub_state(struct msm_vidc_inst *inst, enum msm_vidc_sub_state sub_state)
>> +{
>> +	return (inst->sub_state & sub_state);
>> +}
> Why are there 2 separate funcs for core and inst? Don't we have
> a pointer within one to the other?
> 
> 
core and instance sub states are maintained differently for ex in SSR, we
need to check the core sub state, if we combine instance and core state
checks, we won't know against which sub state we should check.
> [...]
> 

>> +
>> +int msm_vidc_update_state(struct msm_vidc_inst *inst,
>> +			  enum msm_vidc_state request_state, const char *func)
>> +{
>> +	struct msm_vidc_state_handle *state_handle = NULL;
>> +	int rc = 0;
> rc is unused
> 
> [...]
> 
>> +static int msm_vidc_set_sub_state(struct msm_vidc_inst *inst,
>> +				  enum msm_vidc_sub_state sub_state, const char *func)
>> +{
>> +	char sub_state_name[MAX_NAME_LENGTH];
>> +	int cnt, rc = 0;
> ditto
> 
Thanks for pointing these out, will remove all unused rc.

Thanks,
Dikshita
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 16/33] iris: add helpers for media format
  2023-07-28 17:55   ` Konrad Dybcio
@ 2023-08-14 19:18     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:18 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:25 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> Add helpers to calculate stride, scanline, buffer size
>> etc. for different media formats.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> [...]
> 
> 
>> +
>> +#ifndef MSM_MEDIA_ALIGN
>> +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\
>> +	((((__sz) + (__align) - 1) / (__align)) * (__align)) :\
>> +	(((__sz) + (__align) - 1) & (~((__align) - 1))))
> <linux/align.h>?
> 
sure, will replace with standard ALIGN macro
>> +#endif
>> +
>> +#ifndef MSM_MEDIA_ROUNDUP
>> +#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r))
>> +#endif
>> +
>> +/*
>> + * Function arguments:
>> + * @v4l2_fmt
>> + * @width
>> + * Progressive: width
>> + * Interlaced: width
>> + */
> Kerneldoc would be cooler
> 
Sure, will take care of this in next version.
> [...]
> 
>> +static inline unsigned int video_rgb_stride_pix(unsigned int colorformat,
>> +						unsigned int width)
>> +{
>> +	unsigned int bpp = 4;
> Always?
Will check more on this if all supported RGB formats have bpp as 4.

Thanks,
Dikshita
> 
> 
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues
  2023-07-28 17:58   ` Konrad Dybcio
@ 2023-08-14 19:19     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:19 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:28 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> This implements functions to allocate and update the shared memory
>> used for sending commands to firmware and receiving messages from
>> firmware.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../platform/qcom/iris/vidc/inc/venus_hfi_queue.h  |  89 ++++
>>  .../platform/qcom/iris/vidc/src/venus_hfi_queue.c  | 537 +++++++++++++++++++++
>>  2 files changed, 626 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>>  create mode 100644 drivers/media/platform/qcom/iris/vidc/src/venus_hfi_queue.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>> new file mode 100644
>> index 0000000..f533811
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/vidc/inc/venus_hfi_queue.h
>> @@ -0,0 +1,89 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef _VENUS_HFI_QUEUE_H_
>> +#define _VENUS_HFI_QUEUE_H_
>> +
>> +#include <linux/types.h>
>> +
>> +#include "msm_vidc_internal.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		0
>> +#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q		1
>> +#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q		2
>> +#define HFI_MASK_QHDR_STATUS			0x000000ff
> GENMASK, BIT()..
> 
sure, will explore these standard macros and use wherever possible.
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth
  2023-07-28 18:09   ` Konrad Dybcio
@ 2023-08-14 19:21     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:21 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:39 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the logic to compute bus bandwidth required by encoder
>> or decoder for a specific usecase. It takes input as various video
>> usecase parameters as configured by clients.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
> [...]
> 
>> +/* 100x */
>> +static u32 dpbopb_ubwc30_cr_table_cratio_iris3[7][12] = {
> const?
> 
> [...]
> 
>> +
>> +	llc_enabled_ref_y_rd = (codec_input.status_llc_onoff) ? 1 : 0;
>> +	llc_enable_ref_crcb_rd = (codec_input.status_llc_onoff) ? 1 : 0;
>> +	/* H265D BSE tlb in LLC will be pored in Kailua */
> ?
> 
>> +	llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0;
> "? 1 : 0" is fancy bool conversion (!!x)
> 
Hi Konrad,

we will remove this bus calculation logic and move to static bus bandwidth
table in next version so this file will be removed.

Thanks,
Dikshita
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency
  2023-07-28 18:13   ` Konrad Dybcio
@ 2023-08-14 19:25     ` Dikshita Agarwal
  0 siblings, 0 replies; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:25 UTC (permalink / raw)
  To: Konrad Dybcio, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm



On 7/28/2023 11:43 PM, Konrad Dybcio wrote:
> On 28.07.2023 15:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements the logic to computer the required clock frequency
>> by encoder or decoder for a specific usecase. It considers the input
>> as various parameters configured by client for that usecase.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>  .../iris/variant/iris3/src/msm_vidc_clock_iris3.c  | 627 +++++++++++++++++++++
>>  1 file changed, 627 insertions(+)
>>  create mode 100644 drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
>>
>> diff --git a/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
>> new file mode 100644
>> index 0000000..6665aef
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_clock_iris3.c
>> @@ -0,0 +1,627 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include "msm_vidc_debug.h"
>> +
>> +#define ENABLE_FINEBITRATE_SUBUHD60 0
>> +#include "perf_static_model.h"
>> +
>> +/*
>> + * Chipset Generation Technology: SW/FW overhead profiling
>> + * need update with new numbers
>> + */
>> +static u32 frequency_table_iris3[2][6] = {
> I think it's the third repetition of the same (ftbl + OPP)
> 
Sure, will check and do the needful.

>> +	/* //make lowsvs_D1 as invalid; */
>> +	{533, 444, 366, 338, 240, 0},
>> +	{800, 666, 549, 507, 360, 0},
>> +};
>> +
>> + /* Tensilica cycles */
>> +#define DECODER_VPP_FW_OVERHEAD_IRIS3                                                  66234
>> +
>> +/* Tensilica cycles; this is measured in Lahaina 1stage with FW profiling */
> Is it gonna differ for other SoCs? Especially that 8350 has IRIS2?
> 
>> +#define DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3                                         93000
>> +
>> +#define DECODER_VSP_FW_OVERHEAD_IRIS3 \
>> +	(DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 - DECODER_VPP_FW_OVERHEAD_IRIS3)
>> +
>> +/* Tensilica cycles; encoder has ARP register */
>> +#define ENCODER_VPP_FW_OVERHEAD_IRIS3                                                  48405
>> +
>> +#define ENCODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS3 \
>> +	(ENCODER_VPP_FW_OVERHEAD_IRIS3 + DECODER_VSP_FW_OVERHEAD_IRIS3)
>> +
>> +#define DECODER_SW_OVERHEAD_IRIS3                                                      489583
>> +#define ENCODER_SW_OVERHEAD_IRIS3                                                      489583
>> +
>> +/* Video IP Core Technology: pipefloor and pipe penlaty */
>> +static u32 decoder_vpp_target_clk_per_mb_iris3 = 200;
> Why is this a variable?

Agree, this doesn't need to be a variable, will convert to macro.
> 
> [...]
> 
>> +
>> +/* 8KUHD60; UHD240; 1080p960  with B */
>> +static u32 fp_pixel_count_bar0 = 3840 * 2160 * 240;
>> +/* 8KUHD60; UHD240; 1080p960  without B */
>> +static u32 fp_pixel_count_bar1 = 3840 * 2160 * 240;
> Not sure what the 'B' is, but the entries are the same. And looks like
> there's:
> 
> - no need for it to be a variable
> - maybe you could make this a macro or just a simple multiplication
> 
B here is B frames and I agree these can be converted to macros.
> [...]
> 
>> +u32 get_bitrate_entry(u32 pixle_count)
> pixle -> pixel, checkpatch should point out typos
> 
> [...]
Ah! Thanks for pointing it out, checkpatch didn't complain about it, will
fix it.
> 
>> +static int calculate_vsp_min_freq(struct api_calculation_input codec_input,
>> +				  struct api_calculation_freq_output *codec_output)
>> +{
>> +	/*
>> +	 * VSP calculation
>> +	 * different methodology from Lahaina
>> +	 */
> Not sure if that comment is useful to the reader.
> 
> [...]
> 
right, will remove
> 
>> +
>> +static u32 calculate_pipe_penalty(struct api_calculation_input codec_input)
>> +{
>> +	u32 pipe_penalty_codec = 0;
>> +
>> +	/* decoder */
>> +	if (codec_input.decoder_or_encoder == CODEC_DECODER)
>> +		pipe_penalty_codec = pipe_penalty_iris3[0][0];
>> +	else
>> +		pipe_penalty_codec = 101;
> Add a define for this magic number?
> 
> Also, return the value instead of assigning it and doing the same
will fix in next version

Thanks,
Dikshita
> 
> 
> Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550
  2023-07-28 14:13   ` Dmitry Baryshkov
@ 2023-08-14 19:35     ` Dikshita Agarwal
  2023-08-14 21:17       ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 19:35 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 7:43 PM, Dmitry Baryshkov wrote:
> On 28/07/2023 16:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements all the capabilities supported by sm8550.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
>>   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727
>> ++++++++++++++++++++
>>   2 files changed, 1741 insertions(+)
>>   create mode 100644
>> drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>>   create mode 100644
>> drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>>
>> diff --git
>> a/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>> b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>> new file mode 100644
>> index 0000000..0a2f172
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
>> reserved.
>> + */
>> +
>> +#ifndef _MSM_VIDC_SM8550_H_
>> +#define _MSM_VIDC_SM8550_H_
>> +
>> +#include "msm_vidc_core.h"
>> +
>> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core);
>> +
>> +#endif // _MSM_VIDC_SM8550_H_
>> diff --git
>> a/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>> b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>> new file mode 100644
>> index 0000000..2408556
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
>> @@ -0,0 +1,1727 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
>> reserved.
>> + */
>> +
>> +#include <dt-bindings/clock/qcom,sm8550-gcc.h>
>> +#include <dt-bindings/clock/qcom,sm8450-videocc.h>
>> +
>> +#include "hfi_command.h"
>> +#include "hfi_property.h"
>> +#include "msm_vidc_control.h"
>> +#include "msm_vidc_debug.h"
>> +#include "msm_vidc_iris3.h"
>> +#include "msm_vidc_sm8550.h"
>> +#include "msm_vidc_platform.h"
>> +
>> +/* version: major[24:31], minor[16:23], revision[0:15] */
>> +#define DRIVER_VERSION          0x04000000
>> +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
>> +#define MAX_BASE_LAYER_PRIORITY_ID 63
>> +#define MAX_OP_POINT            31
>> +#define MAX_BITRATE             245000000
>> +#define DEFAULT_BITRATE         20000000
>> +#define MINIMUM_FPS             1
>> +#define MAXIMUM_FPS             480
>> +#define MAXIMUM_DEC_FPS         960
>> +#define MAX_QP                  51
>> +#define DEFAULT_QP              20
>> +#define MAX_CONSTANT_QUALITY    100
>> +#define MIN_SLICE_BYTE_SIZE     512
>> +#define MAX_SLICE_BYTE_SIZE       \
>> +    ((MAX_BITRATE) >> 3)
>> +#define MAX_SLICE_MB_SIZE         \
>> +    (((4096 + 15) >> 4) * ((2304 + 15) >> 4))
>> +
>> +#define ENC     MSM_VIDC_ENCODER
>> +#define DEC     MSM_VIDC_DECODER
>> +#define H264    MSM_VIDC_H264
>> +#define HEVC    MSM_VIDC_HEVC
>> +#define VP9     MSM_VIDC_VP9
> 
> Another redefinition. Inline it.
> >> +#define CODECS_ALL     (H264 | HEVC | VP9)
>> +#define MAXIMUM_OVERRIDE_VP9_FPS 200
>> +
>> +static struct codec_info codec_data_sm8550[] = {
>> +    {
>> +        .v4l2_codec  = V4L2_PIX_FMT_H264,
>> +        .vidc_codec  = MSM_VIDC_H264,
>> +        .pixfmt_name = "AVC",
> 
> Have you considered using existing code which enumerates formats? For
> example, it is much better to refactor v4l_fill_fmtdesc() to allow getting
> the description instead of adding your own names here.
> Not to mention that printk supports %p4cc for printing fourcc values. I
> hope you knew that.
> 
Sure, will explore more on this.
>> +    },
>> +    {
>> +        .v4l2_codec  = V4L2_PIX_FMT_HEVC,
>> +        .vidc_codec  = MSM_VIDC_HEVC,
>> +        .pixfmt_name = "HEVC",
>> +    },
>> +    {
>> +        .v4l2_codec  = V4L2_PIX_FMT_VP9,
>> +        .vidc_codec  = MSM_VIDC_VP9,
>> +        .pixfmt_name = "VP9",
>> +    },
>> +};
>> +
>> +static struct color_format_info color_format_data_sm8550[] = {
>> +    {
>> +        .v4l2_color_format = V4L2_PIX_FMT_NV12,
>> +        .vidc_color_format = MSM_VIDC_FMT_NV12,
>> +        .pixfmt_name       = "NV12",
>> +    },
>> +    {
>> +        .v4l2_color_format = V4L2_PIX_FMT_NV21,
>> +        .vidc_color_format = MSM_VIDC_FMT_NV21,
>> +        .pixfmt_name       = "NV21",
>> +    },
>> +    {
>> +        .v4l2_color_format = V4L2_PIX_FMT_QC08C,
>> +        .vidc_color_format = MSM_VIDC_FMT_NV12C,
>> +        .pixfmt_name       = "NV12C",
>> +    },
>> +    {
>> +        .v4l2_color_format = V4L2_PIX_FMT_QC10C,
>> +        .vidc_color_format = MSM_VIDC_FMT_TP10C,
>> +        .pixfmt_name       = "TP10C",
>> +    },
>> +    {
>> +        .v4l2_color_format = V4L2_PIX_FMT_RGBA32,
>> +        .vidc_color_format = MSM_VIDC_FMT_RGBA8888,
>> +        .pixfmt_name       = "RGBA",
>> +    },
>> +};
>> +
>> +static struct color_primaries_info color_primaries_data_sm8550[] = {
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_DEFAULT,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_RESERVED,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_REC709,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT709,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_M,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_BG,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE170M,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT601_525,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE240M,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_ST240M,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_BT2020,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT2020,
>> +    },
>> +    {
>> +        .v4l2_color_primaries  = V4L2_COLORSPACE_DCI_P3,
>> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_RP431_2,
>> +    },
>> +};
>> +
>> +static struct transfer_char_info transfer_char_data_sm8550[] = {
>> +    {
>> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_DEFAULT,
>> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_RESERVED,
>> +    },
>> +    {
>> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_709,
>> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_BT709,
>> +    },
>> +    {
>> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE240M,
>> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST240M,
>> +    },
>> +    {
>> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SRGB,
>> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SRGB_SYCC,
>> +    },
>> +    {
>> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE2084,
>> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ,
>> +    },
>> +};
>> +
>> +static struct matrix_coeff_info matrix_coeff_data_sm8550[] = {
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_DEFAULT,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_RESERVED,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_709,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV709,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV601,
>> +        .vidc_matrix_coeff  =
>> MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_601,
>> +        .vidc_matrix_coeff  =
>> MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_SMPTE240M,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT,
>> +    },
>> +    {
>> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020_CONST_LUM,
>> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT,
>> +    },
>> +};
> 
> Are you going to say that these tables are platform-specific instead of
> being generic to the driver?
> 
future platform can support new codec and that will require new color
primaries. So, yes these can differ for different platforms.
>> +
>> +static struct msm_platform_core_capability core_data_sm8550[] = {
>> +    /* {type, value} */
>> +    {ENC_CODECS, H264 | HEVC},
>> +    {DEC_CODECS, H264 | HEVC | VP9},
>> +    {MAX_SESSION_COUNT, 16},
>> +    {MAX_NUM_720P_SESSIONS, 16},
>> +    {MAX_NUM_1080P_SESSIONS, 16},
>> +    {MAX_NUM_4K_SESSIONS, 8},
>> +    {MAX_NUM_8K_SESSIONS, 2},
>> +    {MAX_RT_MBPF, 174080},    /* (8192x4352)/256 + (4096x2176)/256*/
>> +    {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */
>> +    {MAX_MBPS, 7833600},    /* max_load
>> +                 * 7680x4320@60fps or 3840x2176@240fps
>> +                 * which is greater than 4096x2176@120fps,
>> +                 * 8192x4320@48fps
>> +                 */
>> +    {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */
>> +    {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */
>> +    {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */
>> +    {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */
>> +    {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */
>> +    {MAX_ENH_LAYER_COUNT, 5},
>> +    {NUM_VPP_PIPE, 4},
>> +    {SW_PC, 1},
>> +    {FW_UNLOAD, 0},
>> +    {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */
>> +    {SW_PC_DELAY,         SW_PC_DELAY_VALUE        }, /* 1500 ms
>> (>HW_RESPONSE_TIMEOUT)*/
>> +    {FW_UNLOAD_DELAY,     FW_UNLOAD_DELAY_VALUE    }, /* 3000 ms
>> (>SW_PC_DELAY)*/
>> +    {DCVS, 1},
>> +    {DECODE_BATCH, 1},
>> +    {DECODE_BATCH_TIMEOUT, 200},
>> +    {STATS_TIMEOUT_MS, 2000},
>> +    {NON_FATAL_FAULTS, 1},
>> +    {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING},
> 
> Unless there is a good reason, please change this to be a proper data
> structure instead of being a type-value array. With the T-V it is
> impossible to notice if the value is missing or duplicated. This comment
> also applies to the next 'capability' array.
> 
Core has set of caps. All caps might not be supported for all the hardware.
So it's quite valid to miss a cap entry if its not applicable for that
hardware.
subsequently with caps as enum, it will become easy to copy these caps from
platform to core.

please check msm_vidc_init_core_caps API in [1]

[1]
https://patchwork.linuxtv.org/project/linux-media/patch/1690550624-14642-11-git-send-email-quic_vgarodia@quicinc.com/

>> +};
>> +
>> +static struct msm_platform_inst_capability instance_cap_data_sm8550[] = {
>> +    /* {cap, domain, codec,
>> +     *      min, max, step_or_mask, value,
>> +     *      v4l2_id,
>> +     *      hfi_id,
>> +     *      flags}
>> +     */
>> +    {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920},
>> +
>> +    {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920},
>> +
>> +    {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920},
>> +
>> +    {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920},
>> +
>> +    {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920},
>> +
>> +    {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920},
>> +
>> +    {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080},
>> +
>> +    {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080},
>> +
>> +    {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080},
>> +
>> +    {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080},
>> +
>> +    {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080},
>> +
>> +    {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080},
>> +
>> +    {PIX_FMTS, ENC | DEC, H264,
>> +        MSM_VIDC_FMT_NV12,
>> +        MSM_VIDC_FMT_NV12C,
>> +        MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C,
>> +        MSM_VIDC_FMT_NV12C},
>> +
>> +    {PIX_FMTS, ENC | DEC, HEVC | VP9,
>> +        MSM_VIDC_FMT_NV12,
>> +        MSM_VIDC_FMT_TP10C,
>> +        MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C |
>> +        MSM_VIDC_FMT_TP10C,
>> +        MSM_VIDC_FMT_NV12C},
>> +
>> +    {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4,
>> +        V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
>> +        0,
>> +        CAP_FLAG_VOLATILE},
>> +
>> +    {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL,
>> +        0, 64, 1, 4,
>> +        V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
>> +        HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE},
>> +
>> +    /* (8192 * 4320) / 256 */
>> +    {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240},
>> +
>> +    {MBPF, ENC, HEVC, 36, 138240, 1, 138240},
>> +
>> +    {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240},
>> +
>> +    /* (4096 * 2304) / 256 */
>> +    {MBPF, DEC, VP9, 36, 36864, 1, 36864},
>> +
>> +    /* (4096 * 2304) / 256 */
>> +    {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864},
>> +
>> +    /* Batch Mode Decode */
>> +    /* TODO: update with new values based on updated voltage corner */
>> +    {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816},
>> +
>> +    /* (4096 * 2304) / 256 */
>> +    {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120},
>> +
>> +    {FRAME_RATE, ENC | DEC, CODECS_ALL,
>> +        (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
>> +        1, (DEFAULT_FPS << 16),
>> +        0,
>> +        HFI_PROP_FRAME_RATE,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {OPERATING_RATE, ENC | DEC, CODECS_ALL,
>> +        (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
>> +        1, (DEFAULT_FPS << 16)},
>> +
>> +    {INPUT_RATE, ENC | DEC, CODECS_ALL,
>> +        (MINIMUM_FPS << 16), INT_MAX,
>> +        1, (DEFAULT_FPS << 16)},
>> +
>> +    {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL,
>> +        (MINIMUM_FPS << 16), INT_MAX,
>> +        1, (DEFAULT_FPS << 16)},
>> +
>> +    {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8},
>> +
>> +    {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25},
>> +
>> +    {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25},
>> +
>> +    {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60},
>> +
>> +    {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675},
>> +
>> +    {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200},
>> +
>> +    {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320},
>> +
>> +    {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200},
>> +
>> +    {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583},
>> +
>> +    {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405},
>> +
>> +    {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234},
>> +
>> +    {HFLIP, ENC, CODECS_ALL,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_HFLIP,
>> +        HFI_PROP_FLIP,
>> +        CAP_FLAG_OUTPUT_PORT |
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {VFLIP, ENC, CODECS_ALL,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_VFLIP,
>> +        HFI_PROP_FLIP,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +        CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {ROTATION, ENC, CODECS_ALL,
>> +        0, 270, 90, 0,
>> +        V4L2_CID_ROTATE,
>> +        HFI_PROP_ROTATION,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {HEADER_MODE, ENC, CODECS_ALL,
>> +        V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
>> +        V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
>> +        BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
>> +        BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
>> +        V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
>> +        V4L2_CID_MPEG_VIDEO_HEADER_MODE,
>> +        HFI_PROP_SEQ_HEADER_MODE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR},
>> +
>> +    {WITHOUT_STARTCODE, ENC, CODECS_ALL,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
>> +        HFI_PROP_NAL_LENGTH_FIELD,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {NAL_LENGTH_FIELD, ENC, CODECS_ALL,
>> +        V4L2_MPEG_VIDEO_HEVC_SIZE_0,
>> +        V4L2_MPEG_VIDEO_HEVC_SIZE_4,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4),
>> +        V4L2_MPEG_VIDEO_HEVC_SIZE_0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
>> +        HFI_PROP_NAL_LENGTH_FIELD,
>> +        CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT},
>> +
>> +    /* TODO: Firmware introduced enumeration type for this
>> +     * with and without seq header.
>> +     */
>> +    {REQUEST_I_FRAME, ENC, H264 | HEVC,
>> +        0, 0, 0, 0,
>> +        V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
>> +        HFI_PROP_REQUEST_SYNC_FRAME,
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    /* Enc: Keeping CABAC and CAVLC as same bitrate.
>> +     * Dec: there's no use of Bitrate cap
>> +     */
>> +    {BIT_RATE, ENC, H264 | HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_BITRATE,
>> +        HFI_PROP_TOTAL_BITRATE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +        CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {BITRATE_MODE, ENC, H264,
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
>> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
>> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
>> +        V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
>> +        HFI_PROP_RATE_CONTROL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {BITRATE_MODE, ENC, HEVC,
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_CQ,
>> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
>> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
>> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ),
>> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
>> +        V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
>> +        HFI_PROP_RATE_CONTROL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0,
>> +        160000000, 1, 160000000},
>> +
>> +    {CAVLC_MAX_BITRATE, ENC, H264, 0,
>> +        220000000, 1, 220000000},
>> +
>> +    {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0,
>> +        245000000, 1, 245000000},
>> +
>> +    {NUM_COMV, DEC, CODECS_ALL,
>> +        0, INT_MAX, 1, 0},
>> +
>> +    {LOSSLESS, ENC, HEVC,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU},
>> +
>> +    {FRAME_SKIP_MODE, ENC, H264 | HEVC,
>> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
>> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
>> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
>> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) |
>> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
>> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
>> +        V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {FRAME_RC_ENABLE, ENC, H264 | HEVC,
>> +        0, 1, 1, 1,
>> +        V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE},
>> +
>> +    {CONSTANT_QUALITY, ENC, HEVC,
>> +        1, MAX_CONSTANT_QUALITY, 1, 90,
>> +        V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY,
>> +        HFI_PROP_CONSTANT_QUALITY,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +        CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {GOP_SIZE, ENC, CODECS_ALL,
>> +        0, INT_MAX, 1, 2 * DEFAULT_FPS - 1,
>> +        V4L2_CID_MPEG_VIDEO_GOP_SIZE,
>> +        HFI_PROP_MAX_GOP_FRAMES,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +        CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {GOP_CLOSURE, ENC, H264 | HEVC,
>> +        0, 1, 1, 1,
>> +        V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
>> +        0},
>> +
>> +    {B_FRAME, ENC, H264 | HEVC,
>> +        0, 7, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_B_FRAMES,
>> +        HFI_PROP_MAX_B_FRAMES,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {LTR_COUNT, ENC, H264 | HEVC,
>> +        0, MAX_LTR_FRAME_COUNT_2, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_LTR_COUNT,
>> +        HFI_PROP_LTR_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {USE_LTR, ENC, H264 | HEVC,
>> +        0,
>> +        ((1 << MAX_LTR_FRAME_COUNT_2) - 1),
>> +        0, 0,
>> +        V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES,
>> +        HFI_PROP_LTR_USE,
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {MARK_LTR, ENC, H264 | HEVC,
>> +        INVALID_DEFAULT_MARK_OR_USE_LTR,
>> +        (MAX_LTR_FRAME_COUNT_2 - 1),
>> +        1, INVALID_DEFAULT_MARK_OR_USE_LTR,
>> +        V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX,
>> +        HFI_PROP_LTR_MARK,
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {BASELAYER_PRIORITY, ENC, H264,
>> +        0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID,
>> +        HFI_PROP_BASELAYER_PRIORITYID,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {IR_TYPE, ENC, H264 | HEVC,
>> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
>> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
>> +        BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) |
>> +        BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC),
>> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
>> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {IR_PERIOD, ENC, H264 | HEVC,
>> +        0, INT_MAX, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
>> +        0,
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT |
>> +        CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {AU_DELIMITER, ENC, H264 | HEVC,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
>> +        HFI_PROP_AUD,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {MIN_QUALITY, ENC, H264 | HEVC,
>> +        0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY,
>> +        0,
>> +        HFI_PROP_MAINTAIN_MIN_QUALITY,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {VBV_DELAY, ENC, H264 | HEVC,
>> +        200, 300, 100, 300,
>> +        V4L2_CID_MPEG_VIDEO_VBV_DELAY,
>> +        HFI_PROP_VBV_DELAY,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {PEAK_BITRATE, ENC, H264 | HEVC,
>> +        /* default peak bitrate is 10% larger than avg bitrate */
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
>> +        HFI_PROP_TOTAL_PEAK_BITRATE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {MIN_FRAME_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
>> +        V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
>> +        HFI_PROP_MIN_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {MIN_FRAME_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
>> +        HFI_PROP_MIN_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {I_FRAME_MIN_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
>> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP},
>> +
>> +    {I_FRAME_MIN_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP},
>> +
>> +    {P_FRAME_MIN_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
>> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP},
>> +
>> +    {P_FRAME_MIN_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP},
>> +
>> +    {B_FRAME_MIN_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
>> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP},
>> +
>> +    {B_FRAME_MIN_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP},
>> +
>> +    {MAX_FRAME_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
>> +        HFI_PROP_MAX_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {MAX_FRAME_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
>> +        HFI_PROP_MAX_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {I_FRAME_MAX_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP},
>> +
>> +    {I_FRAME_MAX_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP},
>> +
>> +    {P_FRAME_MAX_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP},
>> +
>> +    {P_FRAME_MAX_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP},
>> +
>> +    {B_FRAME_MAX_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP},
>> +
>> +    {B_FRAME_MAX_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP},
>> +
>> +    {I_FRAME_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {I_FRAME_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {P_FRAME_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {P_FRAME_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {B_FRAME_QP, ENC, HEVC,
>> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {B_FRAME_QP, ENC, H264,
>> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
>> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
>> +        HFI_PROP_QP_PACKED,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {LAYER_TYPE, ENC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
>> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P),
>> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
>> +        HFI_PROP_LAYER_ENCODING_TYPE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LAYER_TYPE, ENC, H264,
>> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
>> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
>> +        BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P),
>> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
>> +        HFI_PROP_LAYER_ENCODING_TYPE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LAYER_ENABLE, ENC, H264,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
>> +        HFI_PROP_LAYER_ENCODING_TYPE,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {LAYER_ENABLE, ENC, HEVC,
>> +        0, 1, 1, 0,
>> +        0,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {ENH_LAYER_COUNT, ENC, HEVC,
>> +        0, 5, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
>> +        HFI_PROP_LAYER_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {ENH_LAYER_COUNT, ENC, H264,
>> +        0, 5, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
>> +        HFI_PROP_LAYER_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L0_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
>> +        HFI_PROP_BITRATE_LAYER1,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L0_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
>> +        HFI_PROP_BITRATE_LAYER1,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L1_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
>> +        HFI_PROP_BITRATE_LAYER2,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L1_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
>> +        HFI_PROP_BITRATE_LAYER2,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L2_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
>> +        HFI_PROP_BITRATE_LAYER3,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L2_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
>> +        HFI_PROP_BITRATE_LAYER3,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L3_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
>> +        HFI_PROP_BITRATE_LAYER4,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +    {L3_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
>> +        HFI_PROP_BITRATE_LAYER4,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L4_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
>> +        HFI_PROP_BITRATE_LAYER5,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L4_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
>> +        HFI_PROP_BITRATE_LAYER5,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L5_BR, ENC, H264,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
>> +        HFI_PROP_BITRATE_LAYER6,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {L5_BR, ENC, HEVC,
>> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
>> +        HFI_PROP_BITRATE_LAYER6,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
>> +            CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {ENTROPY_MODE, ENC, H264,
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
>> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
>> +        V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
>> +        HFI_PROP_CABAC_SESSION,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {ENTROPY_MODE, DEC, H264 | HEVC | VP9,
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
>> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
>> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
>> +        0,
>> +        HFI_PROP_CABAC_SESSION},
>> +
>> +    {PROFILE, ENC | DEC, H264,
>> +        V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
>> +        V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
>> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH),
>> +        V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
>> +        V4L2_CID_MPEG_VIDEO_H264_PROFILE,
>> +        HFI_PROP_PROFILE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {PROFILE, ENC | DEC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
>> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10),
>> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
>> +        HFI_PROP_PROFILE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {PROFILE, DEC, VP9,
>> +        V4L2_MPEG_VIDEO_VP9_PROFILE_0,
>> +        V4L2_MPEG_VIDEO_VP9_PROFILE_2,
>> +        BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2),
>> +        V4L2_MPEG_VIDEO_VP9_PROFILE_0,
>> +        V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
>> +        HFI_PROP_PROFILE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LEVEL, ENC, H264,
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0),
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_5_0,
>> +        V4L2_CID_MPEG_VIDEO_H264_LEVEL,
>> +        HFI_PROP_LEVEL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LEVEL, ENC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_5,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
>> +        HFI_PROP_LEVEL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LEVEL, DEC, H264,
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2),
>> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_1,
>> +        V4L2_CID_MPEG_VIDEO_H264_LEVEL,
>> +        HFI_PROP_LEVEL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LEVEL, DEC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
>> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
>> +        HFI_PROP_LEVEL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LEVEL, DEC, VP9,
>> +        V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
>> +        V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) |
>> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0),
>> +        V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
>> +        V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
>> +        HFI_PROP_LEVEL,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {HEVC_TIER, ENC | DEC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
>> +        V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH),
>> +        V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_TIER,
>> +        HFI_PROP_TIER,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LF_MODE, ENC, H264,
>> +        V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
>> +        DB_H264_DISABLE_SLICE_BOUNDARY,
>> +        BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
>> +        BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
>> +        BIT(DB_H264_DISABLE_SLICE_BOUNDARY),
>> +        V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
>> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
>> +        HFI_PROP_DEBLOCKING_MODE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LF_MODE, ENC, HEVC,
>> +        V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
>> +        DB_HEVC_DISABLE_SLICE_BOUNDARY,
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) |
>> +        BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) |
>> +        BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY),
>> +        V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
>> +        HFI_PROP_DEBLOCKING_MODE,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {LF_ALPHA, ENC, H264,
>> +        -6, 6, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA},
>> +
>> +    {LF_ALPHA, ENC, HEVC,
>> +        -6, 6, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2},
>> +
>> +    {LF_BETA, ENC, H264,
>> +        -6, 6, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA},
>> +
>> +    {LF_BETA, ENC, HEVC,
>> +        -6, 6, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2},
>> +
>> +    {SLICE_MODE, ENC, H264 | HEVC,
>> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
>> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
>> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
>> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) |
>> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES),
>> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
>> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
>> +
>> +    {SLICE_MAX_BYTES, ENC, H264 | HEVC,
>> +        MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE,
>> +        1, MIN_SLICE_BYTE_SIZE,
>> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
>> +        HFI_PROP_MULTI_SLICE_BYTES_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {SLICE_MAX_MB, ENC, H264 | HEVC,
>> +        1, MAX_SLICE_MB_SIZE, 1, 1,
>> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
>> +        HFI_PROP_MULTI_SLICE_MB_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {MB_RC, ENC, H264 | HEVC,
>> +        0, 1, 1, 1,
>> +        V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {TRANSFORM_8X8, ENC, H264,
>> +        0, 1, 1, 1,
>> +        V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
>> +        HFI_PROP_8X8_TRANSFORM,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
>> +        MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET,
>> +        1, MAX_CHROMA_QP_OFFSET,
>> +        V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
>> +        HFI_PROP_CHROMA_QP_OFFSET,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
>> +        HFI_PROP_DECODE_ORDER_OUTPUT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
>> +        0, 1, 1, 0,
>> +        V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
>> +        HFI_PROP_DECODE_ORDER_OUTPUT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
>> +        0, 1, 1, 0,
>> +        0,
>> +        HFI_PROP_DECODE_ORDER_OUTPUT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
>> +        DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
>> +        1, DEFAULT_MAX_HOST_BUF_COUNT,
>> +        0,
>> +        HFI_PROP_BUFFER_HOST_MAX_COUNT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
>> +        DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
>> +        1, DEFAULT_MAX_HOST_BUF_COUNT,
>> +        0,
>> +        HFI_PROP_BUFFER_HOST_MAX_COUNT,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +
>> +    {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1,
>> +        DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
>> +        V4L2_CID_MPEG_VIDEO_MUTE_YUV,
>> +        HFI_PROP_CONCEAL_COLOR_8BIT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1,
>> +        DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
>> +        V4L2_CID_MPEG_VIDEO_MUTE_YUV,
>> +        HFI_PROP_CONCEAL_COLOR_10BIT,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {STAGE, DEC | ENC, CODECS_ALL,
>> +        MSM_VIDC_STAGE_1,
>> +        MSM_VIDC_STAGE_2, 1,
>> +        MSM_VIDC_STAGE_2,
>> +        0,
>> +        HFI_PROP_STAGE},
>> +
>> +    {PIPE, DEC | ENC, CODECS_ALL,
>> +        MSM_VIDC_PIPE_1,
>> +        MSM_VIDC_PIPE_4, 1,
>> +        MSM_VIDC_PIPE_4,
>> +        0,
>> +        HFI_PROP_PIPE},
>> +
>> +    {POC, DEC, H264, 0, 2, 1, 1,
>> +        0,
>> +        HFI_PROP_PIC_ORDER_CNT_TYPE},
>> +
>> +    {QUALITY_MODE, ENC, CODECS_ALL,
>> +        MSM_VIDC_MAX_QUALITY_MODE,
>> +        MSM_VIDC_POWER_SAVE_MODE, 1,
>> +        MSM_VIDC_POWER_SAVE_MODE},
>> +
>> +    {CODED_FRAMES, DEC, H264 | HEVC,
>> +        CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE,
>> +        1, CODED_FRAMES_PROGRESSIVE,
>> +        0,
>> +        HFI_PROP_CODED_FRAMES},
>> +
>> +    {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8,
>> +        0,
>> +        HFI_PROP_LUMA_CHROMA_BIT_DEPTH},
>> +
>> +    {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0,
>> +        0},
>> +
>> +    {DEFAULT_HEADER, DEC, CODECS_ALL,
>> +        0, 1, 1, 0,
>> +        0,
>> +        HFI_PROP_DEC_DEFAULT_HEADER},
>> +
>> +    {RAP_FRAME, DEC, CODECS_ALL,
>> +        0, 1, 1, 1,
>> +        0,
>> +        HFI_PROP_DEC_START_FROM_RAP_FRAME,
>> +        CAP_FLAG_INPUT_PORT},
>> +
>> +    {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL,
>> +        0, 1, 1, 1,
>> +        0,
>> +        HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME,
>> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
>> +
>> +    {ALL_INTRA, ENC, H264 | HEVC,
>> +        0, 1, 1, 0,
>> +        0,
>> +        0,
>> +        CAP_FLAG_OUTPUT_PORT},
>> +};
>> +
>> +static struct msm_platform_inst_cap_dependency
>> instance_cap_dependency_data_sm8550[] = {
>> +    /* {cap, domain, codec,
>> +     *      children,
>> +     *      adjust, set}
>> +     */
>> +
>> +    {PIX_FMTS, ENC, H264,
>> +        {IR_PERIOD}},
>> +
>> +    {PIX_FMTS, ENC, HEVC,
>> +        {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP,
>> +            B_FRAME_QP, MIN_QUALITY, IR_PERIOD, LTR_COUNT}},
>> +
>> +    {PIX_FMTS, DEC, HEVC,
>> +        {PROFILE}},
>> +
>> +    {FRAME_RATE, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_q16},
>> +
>> +    {HFLIP, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_flip},
>> +
>> +    {VFLIP, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_flip},
>> +
>> +    {ROTATION, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_rotation},
>> +
>> +    {HEADER_MODE, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_header_mode},
>> +
>> +    {WITHOUT_STARTCODE, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_nal_length},
>> +
>> +    {REQUEST_I_FRAME, ENC, H264 | HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_req_sync_frame},
>> +
>> +    {BIT_RATE, ENC, H264,
>> +        {PEAK_BITRATE, L0_BR},
>> +        msm_vidc_adjust_bitrate,
>> +        msm_vidc_set_bitrate},
>> +
>> +    {BIT_RATE, ENC, HEVC,
>> +        {PEAK_BITRATE, L0_BR},
>> +        msm_vidc_adjust_bitrate,
>> +        msm_vidc_set_bitrate},
>> +
>> +    {BITRATE_MODE, ENC, H264,
>> +        {LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
>> +            B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE,
>> +            MIN_QUALITY, VBV_DELAY,
>> +            PEAK_BITRATE, SLICE_MODE},
>> +        msm_vidc_adjust_bitrate_mode,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {BITRATE_MODE, ENC, HEVC,
>> +        {LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
>> +            B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT,
>> +            BIT_RATE, MIN_QUALITY, VBV_DELAY,
>> +            PEAK_BITRATE, SLICE_MODE},
>> +        msm_vidc_adjust_bitrate_mode,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {CONSTANT_QUALITY, ENC, HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_constant_quality},
>> +
>> +    {GOP_SIZE, ENC, CODECS_ALL,
>> +        {ALL_INTRA},
>> +        msm_vidc_adjust_gop_size,
>> +        msm_vidc_set_gop_size},
>> +
>> +    {B_FRAME, ENC, H264 | HEVC,
>> +        {ALL_INTRA},
>> +        msm_vidc_adjust_b_frame,
>> +        msm_vidc_set_u32},
>> +
>> +    {LTR_COUNT, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_ltr_count,
>> +        msm_vidc_set_u32},
>> +
>> +    {USE_LTR, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_use_ltr,
>> +        msm_vidc_set_use_and_mark_ltr},
>> +
>> +    {MARK_LTR, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_mark_ltr,
>> +        msm_vidc_set_use_and_mark_ltr},
>> +
>> +    {IR_PERIOD, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_ir_period,
>> +        msm_vidc_set_ir_period},
>> +
>> +    {AU_DELIMITER, ENC, H264 | HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32},
>> +
>> +    {MIN_QUALITY, ENC, H264,
>> +        {0},
>> +        msm_vidc_adjust_min_quality,
>> +        msm_vidc_set_u32},
>> +
>> +    {MIN_QUALITY, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_min_quality,
>> +        msm_vidc_set_u32},
>> +
>> +    {VBV_DELAY, ENC, H264 | HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_cbr_related_properties},
>> +
>> +    {PEAK_BITRATE, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_peak_bitrate,
>> +        msm_vidc_set_cbr_related_properties},
>> +
>> +    {MIN_FRAME_QP, ENC, H264,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_min_qp},
>> +
>> +    {MIN_FRAME_QP, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_hevc_min_qp,
>> +        msm_vidc_set_min_qp},
>> +
>> +    {MAX_FRAME_QP, ENC, H264,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_max_qp},
>> +
>> +    {MAX_FRAME_QP, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_hevc_max_qp,
>> +        msm_vidc_set_max_qp},
>> +
>> +    {I_FRAME_QP, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_hevc_i_frame_qp,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {I_FRAME_QP, ENC, H264,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {P_FRAME_QP, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_hevc_p_frame_qp,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {P_FRAME_QP, ENC, H264,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {B_FRAME_QP, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_hevc_b_frame_qp,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {B_FRAME_QP, ENC, H264,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_frame_qp},
>> +
>> +    {LAYER_TYPE, ENC, H264 | HEVC,
>> +        {LTR_COUNT}},
>> +
>> +    {LAYER_ENABLE, ENC, H264 | HEVC,
>> +        {0}},
>> +
>> +    {ENH_LAYER_COUNT, ENC, H264 | HEVC,
>> +        {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE,
>> +            LTR_COUNT},
>> +        msm_vidc_adjust_layer_count,
>> +        msm_vidc_set_layer_count_and_type},
>> +
>> +    {L0_BR, ENC, H264 | HEVC,
>> +        {L1_BR},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {L1_BR, ENC, H264 | HEVC,
>> +        {L2_BR},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {L2_BR, ENC, H264 | HEVC,
>> +        {L3_BR},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {L3_BR, ENC, H264 | HEVC,
>> +        {L4_BR},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {L4_BR, ENC, H264 | HEVC,
>> +        {L5_BR},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {L5_BR, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_layer_bitrate,
>> +        msm_vidc_set_layer_bitrate},
>> +
>> +    {ENTROPY_MODE, ENC, H264,
>> +        {BIT_RATE},
>> +        msm_vidc_adjust_entropy_mode,
>> +        msm_vidc_set_u32},
>> +
>> +    {PROFILE, ENC, H264,
>> +        {ENTROPY_MODE, TRANSFORM_8X8},
>> +        NULL,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {PROFILE, DEC, H264,
>> +        {ENTROPY_MODE},
>> +        NULL,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {PROFILE, ENC | DEC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_profile,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {PROFILE, DEC, VP9,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {LEVEL, DEC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {LEVEL, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_level},
>> +
>> +    {HEVC_TIER, ENC | DEC, HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32_enum},
>> +
>> +    {LF_MODE, ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_deblock_mode},
>> +
>> +    {SLICE_MODE, ENC, H264 | HEVC,
>> +        {STAGE},
>> +        msm_vidc_adjust_slice_count,
>> +        msm_vidc_set_slice_count},
>> +
>> +    {TRANSFORM_8X8, ENC, H264,
>> +        {0},
>> +        msm_vidc_adjust_transform_8x8,
>> +        msm_vidc_set_u32},
>> +
>> +    {CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
>> +        {0},
>> +        msm_vidc_adjust_chroma_qp_index_offset,
>> +        msm_vidc_set_chroma_qp_index_offset},
>> +
>> +    {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
>> +        {OUTPUT_ORDER},
>> +        NULL,
>> +        NULL},
>> +
>> +    {DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
>> +        {OUTPUT_ORDER},
>> +        NULL,
>> +        NULL},
>> +
>> +    {OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
>> +        {0},
>> +        msm_vidc_adjust_output_order,
>> +        msm_vidc_set_u32},
>> +
>> +    {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
>> +        {0},
>> +        msm_vidc_adjust_input_buf_host_max_count,
>> +        msm_vidc_set_u32},
>> +
>> +    {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_input_buf_host_max_count,
>> +        msm_vidc_set_u32},
>> +
>> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
>> +        {0},
>> +        msm_vidc_adjust_output_buf_host_max_count,
>> +        msm_vidc_set_u32},
>> +
>> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
>> +        {0},
>> +        msm_vidc_adjust_output_buf_host_max_count,
>> +        msm_vidc_set_u32},
>> +
>> +    {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32_packed},
>> +
>> +    {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32_packed},
>> +
>> +    {STAGE, ENC | DEC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_stage},
>> +
>> +    {STAGE, ENC, H264 | HEVC,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_stage},
>> +
>> +    {STAGE, DEC, H264 | HEVC | VP9,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_stage},
>> +
>> +    {PIPE, DEC | ENC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_pipe},
>> +
>> +    {RAP_FRAME, DEC, CODECS_ALL,
>> +        {0},
>> +        NULL,
>> +        msm_vidc_set_u32},
>> +
>> +    {ALL_INTRA, ENC, H264 | HEVC,
>> +        {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE},
>> +        msm_vidc_adjust_all_intra,
>> +        NULL},
>> +};
>> +
>> +/* Default UBWC config for LPDDR5 */
>> +static struct msm_vidc_ubwc_config_data ubwc_config_sm8550[] = {
>> +    UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1),
>> +};
>> +
>> +static struct msm_vidc_format_capability format_data_sm8550 = {
>> +    .codec_info = codec_data_sm8550,
>> +    .codec_info_size = ARRAY_SIZE(codec_data_sm8550),
>> +    .color_format_info = color_format_data_sm8550,
>> +    .color_format_info_size = ARRAY_SIZE(color_format_data_sm8550),
>> +    .color_prim_info = color_primaries_data_sm8550,
>> +    .color_prim_info_size = ARRAY_SIZE(color_primaries_data_sm8550),
>> +    .transfer_char_info = transfer_char_data_sm8550,
>> +    .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_sm8550),
>> +    .matrix_coeff_info = matrix_coeff_data_sm8550,
>> +    .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_sm8550),
>> +};
>> +
>> +/* name, min_kbps, max_kbps */
>> +static const struct bw_table sm8550_bw_table[] = {
>> +    { "venus-cnoc",  1000, 1000     },
>> +    { "venus-ddr",   1000, 15000000 },
> 
> We have OPP tables for that. There is no need to limit the min/max, just
> put it to OPP.
> 
This table is used to vote for min and max bus bandwidth.
for some test vector with bad picture order count, ref count can be huge,
so DPB needs to be filled with high number of reference frames to process
current frames, this needs faster frame processing so to address such
cases, driver vote for max bus bandwidth.
for some cases, when system is in suspend state, there might be some
residual transitions happening for which driver needs to vote for min
frequency during suspend state.
>> +};
>> +
>> +/* name */
>> +static const struct pd_table sm8550_pd_table[] = {
>> +    { "iris-ctl" },
>> +    { "vcodec"   },
>> +};
>> +
>> +/* name */
>> +static const char * const sm8550_opp_table[] = { "mx", "mmcx", NULL };
>> +
>> +/* name, clock id, scaling */
>> +static const struct clk_table sm8550_clk_table[] = {
>> +    { "gcc_video_axi0",         GCC_VIDEO_AXI0_CLK,     0 },
>> +    { "core_clk",               VIDEO_CC_MVS0C_CLK,     0 },
>> +    { "vcodec_clk",             VIDEO_CC_MVS0_CLK,      1 },
>> +};
> 
> This strucuture looks like a perfect candidate to be replaced by
> devm_clk_bulk_get_all().
> 
Nice suggestion, will explore this.
>> +
>> +/* name, exclusive_release */
>> +static const struct clk_rst_table sm8550_clk_reset_table[] = {
>> +    { "video_axi_reset",        0  },
> 
> Can we assume that resets are generic at least?
> 
reset clocks can change for different hardware.
>> +};
>> +
>> +/* name, start, size, secure, dma_coherant, region, dma_mask */
>> +const struct context_bank_table sm8550_context_bank_table[] = {
>> +    {"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1,
>> MSM_VIDC_NON_SECURE, 0xe0000000 - 1},
>> +    {"qcom,vidc,cb-sec-non-pxl",   0x01000000, 0x24800000, 1, 0,
>> MSM_VIDC_SECURE_NONPIXEL,  0 },
> 
> Aren't these a properties of subdevices? If so, why are you putting them here?
> 
Will remove these in next version.
>> +};
>> +
>> +/* freq */
>> +static struct freq_table sm8550_freq_table[] = {
>> +    {533333333}, {444000000}, {366000000}, {338000000}, {240000000}
> 
> OPP table contents.
> 
we are using this freq table at multiple places apart from voting like
- setting freq to turbo for few use cases
- limiting the freq to NOM
- changing the frequency levels based on DCVS
hence this table is need.
>> +};
>> +
>> +/* register, value, mask */
>> +static const struct reg_preset_table sm8550_reg_preset_table[] = {
>> +    { 0xB0088, 0x0, 0x11 },
>> +};
>> +
>> +/* decoder properties */
>> +static const u32 sm8550_vdec_psc_avc[] = {
>> +    HFI_PROP_BITSTREAM_RESOLUTION,
>> +    HFI_PROP_CROP_OFFSETS,
>> +    HFI_PROP_CODED_FRAMES,
>> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
>> +    HFI_PROP_PIC_ORDER_CNT_TYPE,
>> +    HFI_PROP_PROFILE,
>> +    HFI_PROP_LEVEL,
>> +    HFI_PROP_SIGNAL_COLOR_INFO,
>> +};
>> +
>> +static const u32 sm8550_vdec_psc_hevc[] = {
>> +    HFI_PROP_BITSTREAM_RESOLUTION,
>> +    HFI_PROP_CROP_OFFSETS,
>> +    HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
>> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
>> +    HFI_PROP_PROFILE,
>> +    HFI_PROP_LEVEL,
>> +    HFI_PROP_TIER,
>> +    HFI_PROP_SIGNAL_COLOR_INFO,
>> +};
>> +
>> +static const u32 sm8550_vdec_psc_vp9[] = {
>> +    HFI_PROP_BITSTREAM_RESOLUTION,
>> +    HFI_PROP_CROP_OFFSETS,
>> +    HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
>> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
>> +    HFI_PROP_PROFILE,
>> +    HFI_PROP_LEVEL,
>> +};
>> +
>> +static const u32 sm8550_vdec_input_properties_avc[] = {
>> +    HFI_PROP_NO_OUTPUT,
>> +    HFI_PROP_SUBFRAME_INPUT,
>> +};
>> +
>> +static const u32 sm8550_vdec_input_properties_hevc[] = {
>> +    HFI_PROP_NO_OUTPUT,
>> +    HFI_PROP_SUBFRAME_INPUT,
>> +};
>> +
>> +static const u32 sm8550_vdec_input_properties_vp9[] = {
>> +    HFI_PROP_NO_OUTPUT,
>> +    HFI_PROP_SUBFRAME_INPUT,
>> +};
>> +
>> +static const u32 sm8550_vdec_output_properties_avc[] = {
>> +    HFI_PROP_WORST_COMPRESSION_RATIO,
>> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
>> +    HFI_PROP_PICTURE_TYPE,
>> +    HFI_PROP_DPB_LIST,
>> +    HFI_PROP_CABAC_SESSION,
>> +};
>> +
>> +static const u32 sm8550_vdec_output_properties_hevc[] = {
>> +    HFI_PROP_WORST_COMPRESSION_RATIO,
>> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
>> +    HFI_PROP_PICTURE_TYPE,
>> +    HFI_PROP_DPB_LIST,
>> +};
>> +
>> +static const u32 sm8550_vdec_output_properties_vp9[] = {
>> +    HFI_PROP_WORST_COMPRESSION_RATIO,
>> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
>> +    HFI_PROP_PICTURE_TYPE,
>> +    HFI_PROP_DPB_LIST,
>> +};
>> +
>> +static const struct msm_vidc_platform_data sm8550_data = {
>> +    /* resources dependent on other module */
>> +    .bw_tbl = sm8550_bw_table,
>> +    .bw_tbl_size = ARRAY_SIZE(sm8550_bw_table),
>> +    .clk_tbl = sm8550_clk_table,
>> +    .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table),
>> +    .clk_rst_tbl = sm8550_clk_reset_table,
>> +    .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table),
>> +    .subcache_tbl = NULL,
>> +    .subcache_tbl_size = 0,
>> +
>> +    /* populate context bank */
>> +    .context_bank_tbl = sm8550_context_bank_table,
>> +    .context_bank_tbl_size = ARRAY_SIZE(sm8550_context_bank_table),
>> +
>> +    /* populate power domain and opp table */
>> +    .pd_tbl = sm8550_pd_table,
>> +    .pd_tbl_size = ARRAY_SIZE(sm8550_pd_table),
>> +    .opp_tbl = sm8550_opp_table,
>> +    .opp_tbl_size = ARRAY_SIZE(sm8550_opp_table),
>> +
>> +    /* platform specific resources */
>> +    .freq_tbl = sm8550_freq_table,
>> +    .freq_tbl_size = ARRAY_SIZE(sm8550_freq_table),
>> +    .reg_prst_tbl = sm8550_reg_preset_table,
>> +    .reg_prst_tbl_size = ARRAY_SIZE(sm8550_reg_preset_table),
>> +    .fwname = "vpu30_4v",
>> +    .pas_id = 9,
>> +
>> +    /* caps related resorces */
>> +    .core_data = core_data_sm8550,
>> +    .core_data_size = ARRAY_SIZE(core_data_sm8550),
>> +    .inst_cap_data = instance_cap_data_sm8550,
>> +    .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_sm8550),
>> +    .inst_cap_dependency_data = instance_cap_dependency_data_sm8550,
>> +    .inst_cap_dependency_data_size =
>> ARRAY_SIZE(instance_cap_dependency_data_sm8550),
>> +    .ubwc_config = ubwc_config_sm8550,
>> +    .format_data = &format_data_sm8550,
>> +
>> +    /* decoder properties related*/
>> +    .psc_avc_tbl = sm8550_vdec_psc_avc,
>> +    .psc_avc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_avc),
>> +    .psc_hevc_tbl = sm8550_vdec_psc_hevc,
>> +    .psc_hevc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_hevc),
>> +    .psc_vp9_tbl = sm8550_vdec_psc_vp9,
>> +    .psc_vp9_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_vp9),
>> +    .dec_input_prop_avc = sm8550_vdec_input_properties_avc,
>> +    .dec_input_prop_hevc = sm8550_vdec_input_properties_hevc,
>> +    .dec_input_prop_vp9 = sm8550_vdec_input_properties_vp9,
>> +    .dec_input_prop_size_avc =
>> ARRAY_SIZE(sm8550_vdec_input_properties_avc),
>> +    .dec_input_prop_size_hevc =
>> ARRAY_SIZE(sm8550_vdec_input_properties_hevc),
>> +    .dec_input_prop_size_vp9 =
>> ARRAY_SIZE(sm8550_vdec_input_properties_vp9),
>> +    .dec_output_prop_avc = sm8550_vdec_output_properties_avc,
>> +    .dec_output_prop_hevc = sm8550_vdec_output_properties_hevc,
>> +    .dec_output_prop_vp9 = sm8550_vdec_output_properties_vp9,
>> +    .dec_output_prop_size_avc =
>> ARRAY_SIZE(sm8550_vdec_output_properties_avc),
>> +    .dec_output_prop_size_hevc =
>> ARRAY_SIZE(sm8550_vdec_output_properties_hevc),
>> +    .dec_output_prop_size_vp9 =
>> ARRAY_SIZE(sm8550_vdec_output_properties_vp9),
> 
> Size should come next to the array reference.
correct, will fix in next version
> 
>> +};
>> +
>> +static int msm_vidc_init_data(struct msm_vidc_core *core)
>> +{
>> +    d_vpr_h("%s: initialize sm8550 data\n", __func__);
>> +
>> +    core->platform->data = sm8550_data;
>> +
> 
> Please use of_device_match_data() instead.
> 
Thanks for the suggestion, will implement in next version.

Thanks,
Dikshita
>> +    return 0;
>> +}
>> +
>> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core)
>> +{
>> +    return msm_vidc_init_data(core);
>> +}
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations
  2023-07-28 14:19   ` Dmitry Baryshkov
@ 2023-08-14 20:00     ` Dikshita Agarwal
  2023-08-14 20:59       ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Dikshita Agarwal @ 2023-08-14 20:00 UTC (permalink / raw)
  To: Dmitry Baryshkov, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm



On 7/28/2023 7:49 PM, Dmitry Baryshkov wrote:
> On 28/07/2023 16:23, Vikash Garodia wrote:
>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>
>> This implements iris3 specific buffer size calculation for
>> firmware internal buffers, input and output buffers for
>> encoder and decoder.
>>
>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>> ---
>>   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481
>> ++++++++++++++++++++
>>   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
>>   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 ++++++++
>>   3 files changed, 2095 insertions(+)
>>   create mode 100644
>> drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>>   create mode 100644
>> drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
>>   create mode 100644
>> drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
>>
>> diff --git
>> a/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>> b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>> new file mode 100644
>> index 0000000..cb068ca
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
>> @@ -0,0 +1,1481 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
>> reserved.
>> + */
>> +
>> +#ifndef __HFI_BUFFER_IRIS3__
>> +#define __HFI_BUFFER_IRIS3__
>> +
>> +#include <linux/types.h>
>> +
>> +#include "hfi_property.h"
>> +
>> +typedef u8      HFI_U8;
>> +typedef s8      HFI_S8;
>> +typedef u16     HFI_U16;
>> +typedef s16     HFI_S16;
>> +typedef u32     HFI_U32;
>> +typedef s32     HFI_S32;
>> +typedef u64     HFI_U64;
>> +typedef u32     HFI_BOOL;
> 
> No custom typedefs please.
> 
>> +
>> +#ifndef MIN
>> +#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
>> +#endif
>> +
>> +#ifndef MAX
>> +#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
>> +#endif
> 
> You have seen <linux/minmax.h>, didn't you? If so, why are you adding new
> wrappers?
> 
>> +
>> +#define HFI_ALIGNMENT_4096 (4096)
>> +
>> +#define BUF_SIZE_ALIGN_16 (16)
>> +#define BUF_SIZE_ALIGN_32 (32)
>> +#define BUF_SIZE_ALIGN_64 (64)
>> +#define BUF_SIZE_ALIGN_128 (128)
>> +#define BUF_SIZE_ALIGN_256 (256)
>> +#define BUF_SIZE_ALIGN_512 (512)
>> +#define BUF_SIZE_ALIGN_4096 (4096)
> 
> So nice, so useless.
> 
>> +
>> +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \
>> +    (b) * (b)) : (((a) + (b) - 1) & (~((b) - 1))))
> 
> Can you use ALIGN instead?
> 
>> +
>> +#define HFI_WORKMODE_1 1
>> +#define HFI_WORKMODE_2 2
>> +
>> +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64)
>> +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16)
>> +
>> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8)
>> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32)
>> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8)
>> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16)
>> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4)
>> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48)
>> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4)
>> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24)
>> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4)
>> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16)
>> +
>> +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
>> +    (stride = HFI_ALIGN(frame_width, stride_multiple))
> 
> macros with side actions are not really welcomed. Especially as they do not
> bring any additional value and can be inlined.
> 
>> +
>> +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
>> +    min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \
>> +    min_buf_height_multiple))
>> +
>> +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
>> +    (stride = HFI_ALIGN(frame_width, stride_multiple))
>> +
>> +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
>> +    min_buf_height_multiple) (buf_height = HFI_ALIGN((((frame_height) +
>> 1) \
>> +     >> 1),    min_buf_height_multiple))
>> +
>> +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufsize, y_stride,
>> y_buf_height, \
>> +    uv_buf_size, uv_stride, uv_buf_height) \
>> +    do { \
>> +        y_bufsize = (y_stride * y_buf_height); \
>> +        uv_buf_size = (uv_stride * uv_buf_height); \
>> +        buf_size = HFI_ALIGN(y_bufsize + uv_buf_size, HFI_ALIGNMENT_4096) \
>> +    } while (0)
>> +
>> +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufsize, y_stride,
>> y_buf_height) \
>> +    (y_bufsize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
>> +
>> +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \
>> +    uv_stride, uv_buf_height) \
>> +    (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height,
>> HFI_ALIGNMENT_4096))
>> +
>> +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\
>> +    frame_width, frame_height, y_stride_multiple,\
>> +    y_buffer_height_multiple, uv_stride_multiple, \
>> +    uv_buffer_height_multiple, y_metadata_stride_multiple, \
>> +    y_metadata_buffer_height_multiple, \
>> +    uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \
>> +    do { \
>> +        HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size;   \
>> +        HFI_U32 stride, _height; \
>> +        HFI_U32 half_height = (frame_height + 1) >> 1; \
>> +        HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\
>> +                    y_stride_multiple); \
>> +        HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\
>> +                    y_buffer_height_multiple); \
>> +        HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\
>> +        HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \
>> +                    uv_stride_multiple); \
>> +        HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \
>> +                    uv_buffer_height_multiple); \
>> +        HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\
>> +        HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\
>> +                y_metadata_stride_multiple, \
>> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\
>> +        HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \
>> +                y_metadata_buffer_height_multiple,\
>> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\
>> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \
>> +                _height);    \
>> +        HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\
>> +                uv_metadata_stride_multiple, \
>> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \
>> +        HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\
>> +                uv_metadata_buffer_height_multiple,\
>> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\
>> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \
>> +                 _height); \
>> +        buf_size = (y_buf_size + uv_buf_size + y_meta_size + \
>> +            uv_meta_size) << 1;\
>> +    } while (0)
> 
> Even more macro with side effects. Please consider rewriting them to be
> functions. Small function is usually easier to understand compared to the
> complex macro.
> 
The calculations here are about the size of internal buffers, which is
based on agreed interface between driver and hardware. We will discuss with
hardware team on the suggested changes so that driver and hardware aligned
on the size calculations.

Thanks,
Dikshita
>> +
>> +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width,
>> stride_multiple) \
>> +    do { \
>> +        stride = HFI_ALIGN(frame_width, 192); \
>> +        stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
>> +    } while (0)
>> +
>> +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
>> +                min_buf_height_multiple) \
>> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
>> +
>> +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width,
>> stride_multiple) \
>> +    do { \
>> +        stride = HFI_ALIGN(frame_width, 192); \
>> +        stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
>> +    } while (0)
>> +
>> +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
>> +                min_buf_height_multiple) \
>> +    (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
>> +            min_buf_height_multiple))
>> +
>> +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\
>> +        y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \
>> +    do {    \
>> +        y_buf_size = (y_stride * y_buf_height); \
>> +        uv_buf_size = (uv_stride * uv_buf_height); \
>> +        buf_size = y_buf_size + uv_buf_size \
>> +    } while (0)
>> +
>> +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \
>> +                    y_buf_height) \
>> +    (y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
>> +
>> +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \
>> +                    uv_buf_height) \
>> +    (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height,
>> HFI_ALIGNMENT_4096))
>> +
>> +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride,
>> y_buf_height, \
>> +    uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \
>> +    uv_md_height)\
>> +    do { \
>> +        HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \
>> +        HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\
>> +                        y_buf_height); \
>> +        HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \
>> +                        uv_buf_height); \
>> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \
>> +                        y_md_height); \
>> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \
>> +                        uv_md_height); \
>> +        buf_size = y_data_size + uv_data_size + y_md_size + \
>> +                        uv_md_size; \
>> +    } while (0)
>> +
>> +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width,
>> stride_multiple) \
>> +    (stride = HFI_ALIGN(frame_width * 2, stride_multiple))
>> +
>> +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
>> +                min_buf_height_multiple) \
>> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
>> +
>> +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width,
>> stride_multiple) \
>> +    (stride = HFI_ALIGN(frame_width * 2, stride_multiple))
>> +
>> +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
>> +                min_buf_height_multiple) \
>> +    (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
>> +            min_buf_height_multiple))
>> +
>> +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \
>> +    y_buf_height, uv_data_size, uv_stride, uv_buf_height) \
>> +    do { \
>> +        y_data_size = HFI_ALIGN(y_stride * y_buf_height, \
>> +                HFI_ALIGNMENT_4096);\
>> +        uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \
>> +                HFI_ALIGNMENT_4096); \
>> +        buf_size = y_data_size + uv_data_size; \
>> +    } while (0)
>> +
>> +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \
>> +    (stride = ((frame_width * 3) + stride_multiple - 1) & \
>> +             (0xffffffff - (stride_multiple - 1)))
>> +
>> +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \
>> +            min_buf_height_multiple) \
>> +    (buf_height = ((frame_height + min_buf_height_multiple - 1) & \
>> +            (0xffffffff - (min_buf_height_multiple - 1))))
>> +
>> +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
>> +    (buf_size = ((stride) * (buf_height)))
>> +
>> +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \
>> +    (stride = HFI_ALIGN((frame_width << 2), stride_multiple))
>> +
>> +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \
>> +            min_buf_height_multiple) \
>> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
>> +
>> +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
>> +    (buf_size = (stride) * (buf_height))
>> +
>> +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \
>> +                buf_height) \
>> +    (buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096))
>> +
>> +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \
>> +    metadata_buffer_size, stride, buf_height, _metadata_tride, \
>> +    _metadata_buf_height) \
>> +    do { \
>> +        HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \
>> +                stride, buf_height); \
>> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \
>> +                _metadata_tride, _metadata_buf_height); \
>> +        buf_size = data_buf_size + metadata_buffer_size \
>> +    } while (0)
>> +
>> +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\
>> +    metadata_stride_multiple, tile_width_in_pels) \
>> +    ((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels -
>> 1)) /\
>> +    tile_width_in_pels), metadata_stride_multiple)))
>> +
>> +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height,
>> frame_height, \
>> +    metadata_height_multiple, tile_height_in_pels) \
>> +    ((metadata_buf_height = HFI_ALIGN(((frame_height + \
>> +    (tile_height_in_pels - 1)) / tile_height_in_pels), \
>> +    metadata_height_multiple)))
>> +
>> +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \
>> +    metadata_stride_multiple, tile_width_in_pels) \
>> +    ((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\
>> +    (tile_width_in_pels - 1)) / tile_width_in_pels), \
>> +    metadata_stride_multiple)))
>> +
>> +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height,
>> frame_height,\
>> +    metadata_height_multiple, tile_height_in_pels) \
>> +    (metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \
>> +    (tile_height_in_pels - 1)) / tile_height_in_pels), \
>> +    metadata_height_multiple))
>> +
>> +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \
>> +                    _metadata_buf_height) \
>> +    ((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \
>> +                    HFI_ALIGNMENT_4096)))
>> +
>> +#define BUFFER_ALIGNMENT_512_BYTES 512
>> +#define BUFFER_ALIGNMENT_256_BYTES 256
>> +#define BUFFER_ALIGNMENT_128_BYTES 128
>> +#define BUFFER_ALIGNMENT_64_BYTES 64
>> +#define BUFFER_ALIGNMENT_32_BYTES 32
>> +#define BUFFER_ALIGNMENT_16_BYTES 16
>> +#define BUFFER_ALIGNMENT_8_BYTES 8
>> +#define BUFFER_ALIGNMENT_4_BYTES 4
> 
> -ETOOMUCH.
> 
> [skipped the rest, internal reviewer exception]
> 

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-08-14 18:54     ` Dikshita Agarwal
@ 2023-08-14 20:04       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 108+ messages in thread
From: Krzysztof Kozlowski @ 2023-08-14 20:04 UTC (permalink / raw)
  To: Dikshita Agarwal, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, konrad.dybcio, mchehab, hans.verkuil, linux-kernel,
	linux-media, linux-arm-msm

On 14/08/2023 20:54, Dikshita Agarwal wrote:
>>> +
>>> +	core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL);
>>> +	if (!core) {
>>> +		d_vpr_e("%s: failed to alloc memory for core\n", __func__);
>>
>> Ooops, this for sure did not pass any checks by tools. Sorry, please run
>> basic checks like coccinelle, smatch, sparse, W=1 builds.
>>
> we ran check patch and smatch on this code but no errors were reported.

coccinelle is missing

> please elaborate what issue you see with above code?
>>> +		return -ENOMEM;

We did quite a lot of cleanups long, long time ago removing all unneeded
error messages from memory allocations failures.

Maybe Your use of custom printks() confuses coccinelle, which is a proof
that your code is here an anti-pattern.

...

>>
> Sure, will remove these custom wrapper for locks and use standard
> mutex_lock/unlock APIs directly.
>>> +	allow = msm_vidc_allow_pm_suspend(core);
>>> +
>>> +	if (allow == MSM_VIDC_IGNORE) {
>>> +		d_vpr_h("%s: pm already suspended\n", __func__);
>>
>> So you have bug in PM runtime code? Runtime PM does not suspend devices
>> twice.
>> core is power collapsed in case of idle state when there is no processing
> happening by hardware, this can also change the core state to power_disable.
> this check is ensuring if the core is already in power disable state due to
> that, then no need to suspend it again.

No, you just re-implemented runtime PM.


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations
  2023-08-14 20:00     ` Dikshita Agarwal
@ 2023-08-14 20:59       ` Dmitry Baryshkov
  0 siblings, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-14 20:59 UTC (permalink / raw)
  To: Dikshita Agarwal
  Cc: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm

On Mon, 14 Aug 2023 at 23:00, Dikshita Agarwal
<quic_dikshita@quicinc.com> wrote:
>
>
>
> On 7/28/2023 7:49 PM, Dmitry Baryshkov wrote:
> > On 28/07/2023 16:23, Vikash Garodia wrote:
> >> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >>
> >> This implements iris3 specific buffer size calculation for
> >> firmware internal buffers, input and output buffers for
> >> encoder and decoder.
> >>
> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> >> ---
> >>   .../qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h | 1481
> >> ++++++++++++++++++++
> >>   .../iris/variant/iris3/inc/msm_vidc_buffer_iris3.h |   19 +
> >>   .../iris/variant/iris3/src/msm_vidc_buffer_iris3.c |  595 ++++++++
> >>   3 files changed, 2095 insertions(+)
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/variant/iris3/inc/msm_vidc_buffer_iris3.h
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/variant/iris3/src/msm_vidc_buffer_iris3.c
> >>
> >> diff --git
> >> a/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> >> b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> >> new file mode 100644
> >> index 0000000..cb068ca
> >> --- /dev/null
> >> +++ b/drivers/media/platform/qcom/iris/variant/iris3/inc/hfi_buffer_iris3.h
> >> @@ -0,0 +1,1481 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only */
> >> +/*
> >> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> >> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
> >> reserved.
> >> + */
> >> +
> >> +#ifndef __HFI_BUFFER_IRIS3__
> >> +#define __HFI_BUFFER_IRIS3__
> >> +
> >> +#include <linux/types.h>
> >> +
> >> +#include "hfi_property.h"
> >> +
> >> +typedef u8      HFI_U8;
> >> +typedef s8      HFI_S8;
> >> +typedef u16     HFI_U16;
> >> +typedef s16     HFI_S16;
> >> +typedef u32     HFI_U32;
> >> +typedef s32     HFI_S32;
> >> +typedef u64     HFI_U64;
> >> +typedef u32     HFI_BOOL;
> >
> > No custom typedefs please.
> >
> >> +
> >> +#ifndef MIN
> >> +#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
> >> +#endif
> >> +
> >> +#ifndef MAX
> >> +#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
> >> +#endif
> >
> > You have seen <linux/minmax.h>, didn't you? If so, why are you adding new
> > wrappers?
> >
> >> +
> >> +#define HFI_ALIGNMENT_4096 (4096)
> >> +
> >> +#define BUF_SIZE_ALIGN_16 (16)
> >> +#define BUF_SIZE_ALIGN_32 (32)
> >> +#define BUF_SIZE_ALIGN_64 (64)
> >> +#define BUF_SIZE_ALIGN_128 (128)
> >> +#define BUF_SIZE_ALIGN_256 (256)
> >> +#define BUF_SIZE_ALIGN_512 (512)
> >> +#define BUF_SIZE_ALIGN_4096 (4096)
> >
> > So nice, so useless.
> >
> >> +
> >> +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \
> >> +    (b) * (b)) : (((a) + (b) - 1) & (~((b) - 1))))
> >
> > Can you use ALIGN instead?
> >
> >> +
> >> +#define HFI_WORKMODE_1 1
> >> +#define HFI_WORKMODE_2 2
> >> +
> >> +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64)
> >> +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16)
> >> +
> >> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8)
> >> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32)
> >> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8)
> >> +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16)
> >> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4)
> >> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48)
> >> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4)
> >> +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24)
> >> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4)
> >> +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16)
> >> +
> >> +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
> >> +    (stride = HFI_ALIGN(frame_width, stride_multiple))
> >
> > macros with side actions are not really welcomed. Especially as they do not
> > bring any additional value and can be inlined.
> >
> >> +
> >> +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> >> +    min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \
> >> +    min_buf_height_multiple))
> >> +
> >> +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
> >> +    (stride = HFI_ALIGN(frame_width, stride_multiple))
> >> +
> >> +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> >> +    min_buf_height_multiple) (buf_height = HFI_ALIGN((((frame_height) +
> >> 1) \
> >> +     >> 1),    min_buf_height_multiple))
> >> +
> >> +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufsize, y_stride,
> >> y_buf_height, \
> >> +    uv_buf_size, uv_stride, uv_buf_height) \
> >> +    do { \
> >> +        y_bufsize = (y_stride * y_buf_height); \
> >> +        uv_buf_size = (uv_stride * uv_buf_height); \
> >> +        buf_size = HFI_ALIGN(y_bufsize + uv_buf_size, HFI_ALIGNMENT_4096) \
> >> +    } while (0)
> >> +
> >> +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufsize, y_stride,
> >> y_buf_height) \
> >> +    (y_bufsize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
> >> +
> >> +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \
> >> +    uv_stride, uv_buf_height) \
> >> +    (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height,
> >> HFI_ALIGNMENT_4096))
> >> +
> >> +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\
> >> +    frame_width, frame_height, y_stride_multiple,\
> >> +    y_buffer_height_multiple, uv_stride_multiple, \
> >> +    uv_buffer_height_multiple, y_metadata_stride_multiple, \
> >> +    y_metadata_buffer_height_multiple, \
> >> +    uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \
> >> +    do { \
> >> +        HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size;   \
> >> +        HFI_U32 stride, _height; \
> >> +        HFI_U32 half_height = (frame_height + 1) >> 1; \
> >> +        HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\
> >> +                    y_stride_multiple); \
> >> +        HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\
> >> +                    y_buffer_height_multiple); \
> >> +        HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\
> >> +        HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \
> >> +                    uv_stride_multiple); \
> >> +        HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \
> >> +                    uv_buffer_height_multiple); \
> >> +        HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\
> >> +        HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\
> >> +                y_metadata_stride_multiple, \
> >> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\
> >> +        HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \
> >> +                y_metadata_buffer_height_multiple,\
> >> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\
> >> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \
> >> +                _height);    \
> >> +        HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\
> >> +                uv_metadata_stride_multiple, \
> >> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \
> >> +        HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\
> >> +                uv_metadata_buffer_height_multiple,\
> >> +            HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\
> >> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \
> >> +                 _height); \
> >> +        buf_size = (y_buf_size + uv_buf_size + y_meta_size + \
> >> +            uv_meta_size) << 1;\
> >> +    } while (0)
> >
> > Even more macro with side effects. Please consider rewriting them to be
> > functions. Small function is usually easier to understand compared to the
> > complex macro.
> >
> The calculations here are about the size of internal buffers, which is
> based on agreed interface between driver and hardware. We will discuss with
> hardware team on the suggested changes so that driver and hardware aligned
> on the size calculations.

Any size / interface / buffer calculations are not a reason for the
bad code style.

>
> Thanks,
> Dikshita
> >> +
> >> +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width,
> >> stride_multiple) \
> >> +    do { \
> >> +        stride = HFI_ALIGN(frame_width, 192); \
> >> +        stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
> >> +    } while (0)
> >> +
> >> +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> >> +                min_buf_height_multiple) \
> >> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> >> +
> >> +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width,
> >> stride_multiple) \
> >> +    do { \
> >> +        stride = HFI_ALIGN(frame_width, 192); \
> >> +        stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \
> >> +    } while (0)
> >> +
> >> +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> >> +                min_buf_height_multiple) \
> >> +    (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
> >> +            min_buf_height_multiple))
> >> +
> >> +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\
> >> +        y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \
> >> +    do {    \
> >> +        y_buf_size = (y_stride * y_buf_height); \
> >> +        uv_buf_size = (uv_stride * uv_buf_height); \
> >> +        buf_size = y_buf_size + uv_buf_size \
> >> +    } while (0)
> >> +
> >> +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \
> >> +                    y_buf_height) \
> >> +    (y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096))
> >> +
> >> +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \
> >> +                    uv_buf_height) \
> >> +    (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height,
> >> HFI_ALIGNMENT_4096))
> >> +
> >> +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride,
> >> y_buf_height, \
> >> +    uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \
> >> +    uv_md_height)\
> >> +    do { \
> >> +        HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \
> >> +        HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\
> >> +                        y_buf_height); \
> >> +        HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \
> >> +                        uv_buf_height); \
> >> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \
> >> +                        y_md_height); \
> >> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \
> >> +                        uv_md_height); \
> >> +        buf_size = y_data_size + uv_data_size + y_md_size + \
> >> +                        uv_md_size; \
> >> +    } while (0)
> >> +
> >> +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width,
> >> stride_multiple) \
> >> +    (stride = HFI_ALIGN(frame_width * 2, stride_multiple))
> >> +
> >> +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \
> >> +                min_buf_height_multiple) \
> >> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> >> +
> >> +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width,
> >> stride_multiple) \
> >> +    (stride = HFI_ALIGN(frame_width * 2, stride_multiple))
> >> +
> >> +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \
> >> +                min_buf_height_multiple) \
> >> +    (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \
> >> +            min_buf_height_multiple))
> >> +
> >> +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \
> >> +    y_buf_height, uv_data_size, uv_stride, uv_buf_height) \
> >> +    do { \
> >> +        y_data_size = HFI_ALIGN(y_stride * y_buf_height, \
> >> +                HFI_ALIGNMENT_4096);\
> >> +        uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \
> >> +                HFI_ALIGNMENT_4096); \
> >> +        buf_size = y_data_size + uv_data_size; \
> >> +    } while (0)
> >> +
> >> +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \
> >> +    (stride = ((frame_width * 3) + stride_multiple - 1) & \
> >> +             (0xffffffff - (stride_multiple - 1)))
> >> +
> >> +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \
> >> +            min_buf_height_multiple) \
> >> +    (buf_height = ((frame_height + min_buf_height_multiple - 1) & \
> >> +            (0xffffffff - (min_buf_height_multiple - 1))))
> >> +
> >> +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
> >> +    (buf_size = ((stride) * (buf_height)))
> >> +
> >> +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \
> >> +    (stride = HFI_ALIGN((frame_width << 2), stride_multiple))
> >> +
> >> +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \
> >> +            min_buf_height_multiple) \
> >> +    (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple))
> >> +
> >> +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \
> >> +    (buf_size = (stride) * (buf_height))
> >> +
> >> +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \
> >> +                buf_height) \
> >> +    (buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096))
> >> +
> >> +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \
> >> +    metadata_buffer_size, stride, buf_height, _metadata_tride, \
> >> +    _metadata_buf_height) \
> >> +    do { \
> >> +        HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \
> >> +                stride, buf_height); \
> >> +        HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \
> >> +                _metadata_tride, _metadata_buf_height); \
> >> +        buf_size = data_buf_size + metadata_buffer_size \
> >> +    } while (0)
> >> +
> >> +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\
> >> +    metadata_stride_multiple, tile_width_in_pels) \
> >> +    ((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels -
> >> 1)) /\
> >> +    tile_width_in_pels), metadata_stride_multiple)))
> >> +
> >> +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height,
> >> frame_height, \
> >> +    metadata_height_multiple, tile_height_in_pels) \
> >> +    ((metadata_buf_height = HFI_ALIGN(((frame_height + \
> >> +    (tile_height_in_pels - 1)) / tile_height_in_pels), \
> >> +    metadata_height_multiple)))
> >> +
> >> +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \
> >> +    metadata_stride_multiple, tile_width_in_pels) \
> >> +    ((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\
> >> +    (tile_width_in_pels - 1)) / tile_width_in_pels), \
> >> +    metadata_stride_multiple)))
> >> +
> >> +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height,
> >> frame_height,\
> >> +    metadata_height_multiple, tile_height_in_pels) \
> >> +    (metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \
> >> +    (tile_height_in_pels - 1)) / tile_height_in_pels), \
> >> +    metadata_height_multiple))
> >> +
> >> +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \
> >> +                    _metadata_buf_height) \
> >> +    ((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \
> >> +                    HFI_ALIGNMENT_4096)))
> >> +
> >> +#define BUFFER_ALIGNMENT_512_BYTES 512
> >> +#define BUFFER_ALIGNMENT_256_BYTES 256
> >> +#define BUFFER_ALIGNMENT_128_BYTES 128
> >> +#define BUFFER_ALIGNMENT_64_BYTES 64
> >> +#define BUFFER_ALIGNMENT_32_BYTES 32
> >> +#define BUFFER_ALIGNMENT_16_BYTES 16
> >> +#define BUFFER_ALIGNMENT_8_BYTES 8
> >> +#define BUFFER_ALIGNMENT_4_BYTES 4
> >
> > -ETOOMUCH.
> >
> > [skipped the rest, internal reviewer exception]
> >



-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-08-14 18:58     ` Dikshita Agarwal
@ 2023-08-14 21:03       ` Dmitry Baryshkov
  2023-08-24 15:32         ` Vikash Garodia
  0 siblings, 1 reply; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-14 21:03 UTC (permalink / raw)
  To: Dikshita Agarwal
  Cc: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm

On Mon, 14 Aug 2023 at 21:58, Dikshita Agarwal
<quic_dikshita@quicinc.com> wrote:
>
>
>
> On 7/28/2023 7:19 PM, Dmitry Baryshkov wrote:
> > On 28/07/2023 16:23, Vikash Garodia wrote:
> >> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >>
> >> This implements the platform driver methods, file
> >> operations and v4l2 registration.
> >>
> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> >> ---
> >>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660
> >> +++++++++++++++++++++
> >>   1 file changed, 660 insertions(+)
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> >>
> >> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> >> b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> >> new file mode 100644
> >> index 0000000..43439cb
> >> --- /dev/null
> >> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
> >> @@ -0,0 +1,660 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
> >> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> >> + */
> >> +
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/iommu.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/stringify.h>
> >> +#include <linux/version.h>
> >> +#include <linux/workqueue.h>
> >> +
> >> +#include "msm_vidc_core.h"
> >> +#include "msm_vidc_debug.h"
> >> +#include "msm_vidc_driver.h"
> >> +#include "msm_vidc_internal.h"
> >> +#include "msm_vidc_memory.h"
> >> +#include "msm_vidc_platform.h"
> >> +#include "msm_vidc_state.h"
> >> +#include "venus_hfi.h"
> >
> > This files are not present yet, so this commit doesn't have a change of
> > being compiled in any way.
> >
> >> +
> >> +#define BASE_DEVICE_NUMBER 32
> >> +
> >> +struct msm_vidc_core *g_core;
> >> +
> >> +static inline bool is_video_device(struct device *dev)
> >> +{
> >> +    return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
> >
> > Are you going to add future platforms to this list? Please don't duplicate
> > of_match_data here.
> > Sure, Will remove this API in next version.
> >> +}
> >> +
> >> +static inline bool is_video_context_bank_device(struct device *dev)
> >> +{
> >> +    return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
> >> +}
> >> +
> >> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
> >> +{
> >> +    struct msm_vidc_resource *res = NULL;
> >> +    int rc = 0;
> >> +
> >> +    res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
> >> +    if (!res) {
> >> +        d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
> >
> > Where is this macro defined? Please structure your comments in a logical
> > way, so that one can read them from the beginning and understand what is
> > going one.
> >
> > This is not to mention that adding such debugging wrappers doesn't have a
> > lot of value.
> >
> I understand the concern here, will remove the custom debug wrappers in
> next version.
> >> +        return -ENOMEM;
> >> +    }
> >> +    core->resource = res;
> >> +
> >> +    rc = call_res_op(core, init, core);
> >
> > What is call_res_op?
> >
> This implements the resource ops, but as we don't need the abstraction for
> resource ops, this will be removed in next version.
> >> +    if (rc) {
> >> +        d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
> >> +        return rc;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static const struct of_device_id msm_vidc_dt_match[] = {
> >> +    {.compatible = "qcom,sm8550-vidc"},
> >> +    {.compatible = "qcom,vidc,cb-ns"},
> >> +    MSM_VIDC_EMPTY_BRACE
> >
> > NO!!! Please use {} directly.
> >
> I Understand, will replace with {}.
> >> +};
> >> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
> >> +
> >> +static void msm_vidc_release_video_device(struct video_device *vdev)
> >> +{
> >> +    d_vpr_e("%s: video device released\n", __func__);
> >> +}
> >> +
> >> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
> >> +                         enum msm_vidc_domain_type type)
> >> +{
> >> +    int index;
> >> +
> >> +    if (type == MSM_VIDC_DECODER)
> >> +        index = 0;
> >> +    else if (type == MSM_VIDC_ENCODER)
> >> +        index = 1;
> >> +    else
> >> +        return;
> >
> > You can index by the type instead of converting to index.
> >
> MSM_VIDC_DECODER/MSM_VIDC_ENCODER are bit masks hence can not be used as
> array index and these bit mask values are being used in driver at multiple
> places.

A subdevice can not be a decoder and an encoder at the same time, can
it? So, please replace masks with indices.

> >> +
> >> +    v4l2_m2m_release(core->vdev[index].m2m_dev);
> >> +
> >> +    video_set_drvdata(&core->vdev[index].vdev, NULL);
> >> +    video_unregister_device(&core->vdev[index].vdev);
> >> +}
> >> +
> >> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
> >> +                      enum msm_vidc_domain_type type, int nr)
> >> +{
> >> +    int rc = 0;
> >> +    int index;
> >> +
> >> +    d_vpr_h("%s: domain %d\n", __func__, type);
> >> +
> >> +    if (type == MSM_VIDC_DECODER)
> >> +        index = 0;
> >> +    else if (type == MSM_VIDC_ENCODER)
> >> +        index = 1;
> >> +    else
> >> +        return -EINVAL;
> >> +
> >> +    core->vdev[index].vdev.release =
> >> +        msm_vidc_release_video_device;
> >> +    core->vdev[index].vdev.fops = core->v4l2_file_ops;
> >> +    if (type == MSM_VIDC_DECODER)
> >> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
> >> +    else
> >> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
> >> +    core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
> >> +    core->vdev[index].type = type;
> >> +    core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
> >> +    core->vdev[index].vdev.device_caps =
> >> core->capabilities[DEVICE_CAPS].value;
> >> +    rc = video_register_device(&core->vdev[index].vdev,
> >> +                   VFL_TYPE_VIDEO, nr);
> >> +    if (rc) {
> >> +        d_vpr_e("Failed to register the video device\n");
> >> +        return rc;
> >> +    }
> >> +    video_set_drvdata(&core->vdev[index].vdev, core);
> >> +
> >> +    core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
> >> +    if (IS_ERR(core->vdev[index].m2m_dev)) {
> >> +        d_vpr_e("Failed to initialize V4L2 M2M device\n");
> >> +        rc = PTR_ERR(core->vdev[index].m2m_dev);
> >> +        goto m2m_init_failed;
> >> +    }
> >> +
> >> +    return 0;
> >> +
> >> +m2m_init_failed:
> >> +    video_unregister_device(&core->vdev[index].vdev);
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
> >> +{
> >> +    int rc = 0;
> >> +
> >> +    if (!core) {
> >> +        d_vpr_e("%s: invalid params\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    mutex_destroy(&core->lock);
> >> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> >> +
> >> +    if (core->batch_workq)
> >> +        destroy_workqueue(core->batch_workq);
> >> +
> >> +    if (core->pm_workq)
> >> +        destroy_workqueue(core->pm_workq);
> >> +
> >> +    core->batch_workq = NULL;
> >> +    core->pm_workq = NULL;
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
> >> +{
> >> +    int rc = 0;
> >> +
> >> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
> >> +
> >> +    core->pm_workq = create_singlethread_workqueue("pm_workq");
> >> +    if (!core->pm_workq) {
> >> +        d_vpr_e("%s: create pm workq failed\n", __func__);
> >> +        rc = -EINVAL;
> >> +        goto exit;
> >> +    }
> >> +
> >> +    core->batch_workq = create_singlethread_workqueue("batch_workq");
> >> +    if (!core->batch_workq) {
> >> +        d_vpr_e("%s: create batch workq failed\n", __func__);
> >> +        rc = -EINVAL;
> >> +        goto exit;
> >> +    }
> >> +
> >> +    core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
> >> +    core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size,
> >> GFP_KERNEL);
> >> +    if (!core->packet) {
> >> +        d_vpr_e("%s: failed to alloc core packet\n", __func__);
> >> +        rc = -ENOMEM;
> >> +        goto exit;
> >> +    }
> >> +
> >> +    core->response_packet = devm_kzalloc(&core->pdev->dev,
> >> core->packet_size, GFP_KERNEL);
> >> +    if (!core->packet) {
> >> +        d_vpr_e("%s: failed to alloc core response packet\n", __func__);
> >> +        rc = -ENOMEM;
> >> +        goto exit;
> >> +    }
> >> +
> >> +    mutex_init(&core->lock);
> >> +    INIT_LIST_HEAD(&core->instances);
> >> +    INIT_LIST_HEAD(&core->dangling_instances);
> >> +
> >> +    INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
> >> +    INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
> >> +
> >> +    return 0;
> >> +exit:
> >> +    if (core->batch_workq)
> >> +        destroy_workqueue(core->batch_workq);
> >> +    if (core->pm_workq)
> >> +        destroy_workqueue(core->pm_workq);
> >> +    core->batch_workq = NULL;
> >> +    core->pm_workq = NULL;
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static void msm_vidc_devm_deinit_core(void *res)
> >> +{
> >> +    struct msm_vidc_core *core = res;
> >> +
> >> +    msm_vidc_deinitialize_core(core);
> >> +}
> >> +
> >> +static int msm_vidc_devm_init_core(struct device *dev, struct
> >> msm_vidc_core *core)
> >> +{
> >> +    int rc = 0;
> >> +
> >> +    if (!dev || !core) {
> >> +        d_vpr_e("%s: invalid params\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    rc = msm_vidc_initialize_core(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init failed with %d\n", __func__, rc);
> >> +        return rc;
> >> +    }
> >> +
> >> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void
> >> *)core);
> >> +    if (rc)
> >> +        return -EINVAL;
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static void msm_vidc_devm_debugfs_put(void *res)
> >> +{
> >> +    struct dentry *parent = res;
> >> +
> >> +    debugfs_remove_recursive(parent);
> >> +}
> >> +
> >> +static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev)
> >
> > Why is it called get?
> >
> this will be removed in next version as part of debug wrappers removal
> >
> >> +{
> >> +    struct dentry *parent = NULL;
> >> +    int rc = 0;
> >> +
> >> +    if (!dev) {
> >> +        d_vpr_e("%s: invalid params\n", __func__);
> >> +        return NULL;
> >> +    }
> >> +
> >> +    parent = msm_vidc_debugfs_init_drv();
> >> +    if (!parent)
> >> +        return NULL;
> >> +
> >> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void
> >> *)parent);
> >> +    if (rc)
> >> +        return NULL;
> >> +
> >> +    return parent;
> >> +}
> >> +
> >> +static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
> >> +                       struct device *dev)
> >> +{
> >> +    struct context_bank_info *cb = NULL;
> >> +    int rc = 0;
> >> +
> >> +    cb = msm_vidc_get_context_bank_for_device(core, dev);
> >> +    if (!cb) {
> >> +        d_vpr_e("%s: Failed to get context bank device for %s\n",
> >> +            __func__, dev_name(dev));
> >> +        return -EIO;
> >> +    }
> >> +
> >> +    /* populate dev & domain field */
> >> +    cb->dev = dev;
> >> +    cb->domain = iommu_get_domain_for_dev(cb->dev);
> >> +    if (!cb->domain) {
> >> +        d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__,
> >> dev_name(dev));
> >> +        return -EIO;
> >> +    }
> >> +
> >> +    if (cb->dma_mask) {
> >> +        rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask);
> >> +        if (rc) {
> >> +            d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__);
> >> +            return rc;
> >> +        }
> >> +    }
> >> +
> >> +    /*
> >> +     * configure device segment size and segment boundary to ensure
> >> +     * iommu mapping returns one mapping (which is required for partial
> >> +     * cache operations)
> >> +     */
> >> +    if (!dev->dma_parms)
> >> +        dev->dma_parms =
> >> +            devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
> >> +    dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
> >> +    dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
> >> +
> >> +    iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler,
> >> (void *)core);
> >> +
> >> +    d_vpr_h("%s: name %s addr start %x size %x secure %d\n",
> >> +        __func__, cb->name, cb->addr_range.start,
> >> +        cb->addr_range.size, cb->secure);
> >> +    d_vpr_h("%s: dma_coherant %d region %d dev_name %s domain %pK
> >> dma_mask %llu\n",
> >> +        __func__, cb->dma_coherant, cb->region, dev_name(cb->dev),
> >> +        cb->domain, cb->dma_mask);
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_remove_video_device(struct platform_device *pdev)
> >> +{
> >> +    struct msm_vidc_core *core;
> >> +
> >> +    if (!pdev) {
> >> +        d_vpr_e("%s: invalid input %pK", __func__, pdev);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    core = dev_get_drvdata(&pdev->dev);
> >> +    if (!core) {
> >> +        d_vpr_e("%s: invalid core\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    msm_vidc_core_deinit(core, true);
> >> +    venus_hfi_queue_deinit(core);
> >> +
> >> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> >> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> >> +
> >> +    v4l2_device_unregister(&core->v4l2_dev);
> >> +
> >> +    d_vpr_h("depopulating sub devices\n");
> >> +    /*
> >> +     * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx
> >> +     * When msm_vidc_remove is called for each sub-device, destroy
> >> +     * context-bank mappings.
> >> +     */
> >> +    of_platform_depopulate(&pdev->dev);
> >> +
> >> +    dev_set_drvdata(&pdev->dev, NULL);
> >> +    g_core = NULL;
> >> +    d_vpr_h("%s(): succssful\n", __func__);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int msm_vidc_remove_context_bank(struct platform_device *pdev)
> >> +{
> >> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int msm_vidc_remove(struct platform_device *pdev)
> >> +{
> >> +    /*
> >> +     * Sub devices remove will be triggered by of_platform_depopulate()
> >> +     * after core_deinit(). It return immediately after completing
> >> +     * sub-device remove.
> >> +     */
> >> +    if (is_video_device(&pdev->dev))
> >> +        return msm_vidc_remove_video_device(pdev);
> >> +    else if (is_video_context_bank_device(&pdev->dev))
> >> +        return msm_vidc_remove_context_bank(pdev);
> >> +
> >> +    /* How did we end up here? */
> >> +    WARN_ON(1);
> >> +    return -EINVAL;
> >> +}
> >> +
> >> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
> >> +{
> >> +    int rc = 0;
> >> +    struct msm_vidc_core *core = NULL;
> >> +    int nr = BASE_DEVICE_NUMBER;
> >> +
> >> +    d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
> >> +
> >> +    core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core),
> >> GFP_KERNEL);
> >> +    if (!core) {
> >> +        d_vpr_e("%s: failed to alloc memory for core\n", __func__);
> >> +        return -ENOMEM;
> >> +    }
> >> +    g_core = core;
> >> +
> >> +    core->pdev = pdev;
> >> +    dev_set_drvdata(&pdev->dev, core);
> >> +
> >> +    core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
> >> +    if (!core->debugfs_parent)
> >> +        d_vpr_h("Failed to create debugfs for msm_vidc\n");
> >> +
> >> +    rc = msm_vidc_devm_init_core(&pdev->dev, core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init core failed with %d\n", __func__, rc);
> >> +        goto init_core_failed;
> >> +    }
> >> +
> >> +    rc = msm_vidc_init_platform(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
> >> +        rc = -EINVAL;
> >> +        goto init_plat_failed;
> >> +    }
> >> +
> >> +    rc = msm_vidc_init_resources(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
> >> +        goto init_res_failed;
> >> +    }
> >> +
> >> +    rc = msm_vidc_init_core_caps(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
> >> +        goto init_res_failed;
> >> +    }
> >> +
> >> +    rc = msm_vidc_init_instance_caps(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
> >> +        goto init_inst_caps_fail;
> >> +    }
> >> +
> >> +    core->debugfs_root = msm_vidc_debugfs_init_core(core);
> >> +    if (!core->debugfs_root)
> >> +        d_vpr_h("Failed to init debugfs core\n");
> >> +
> >> +    d_vpr_h("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.
> >> +     */
> >> +    rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
> >> +                  &pdev->dev);
> >> +    if (rc) {
> >> +        d_vpr_e("Failed to trigger probe for sub-devices\n");
> >> +        goto sub_dev_failed;
> >> +    }
> >> +
> >> +    rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
> >> +    if (rc) {
> >> +        d_vpr_e("Failed to register v4l2 device\n");
> >> +        goto v4l2_reg_failed;
> >> +    }
> >> +
> >> +    /* setup the decoder device */
> >> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
> >> +    if (rc) {
> >> +        d_vpr_e("Failed to register video decoder\n");
> >> +        goto dec_reg_failed;
> >> +    }
> >> +
> >> +    /* setup the encoder device */
> >> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
> >> +    if (rc) {
> >> +        d_vpr_e("Failed to register video encoder\n");
> >> +        goto enc_reg_failed;
> >> +    }
> >> +
> >> +    rc = venus_hfi_queue_init(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: interface queues init failed\n", __func__);
> >> +        goto queues_init_failed;
> >> +    }
> >> +
> >> +    rc = msm_vidc_core_init(core);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: sys init failed\n", __func__);
> >> +        goto core_init_failed;
> >> +    }
> >> +
> >> +    d_vpr_h("%s(): succssful\n", __func__);
> >> +
> >> +    return rc;
> >> +
> >> +core_init_failed:
> >> +    venus_hfi_queue_deinit(core);
> >> +queues_init_failed:
> >> +    of_platform_depopulate(&pdev->dev);
> >> +sub_dev_failed:
> >> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
> >> +enc_reg_failed:
> >> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
> >> +dec_reg_failed:
> >> +    v4l2_device_unregister(&core->v4l2_dev);
> >> +v4l2_reg_failed:
> >> +init_inst_caps_fail:
> >> +init_res_failed:
> >> +init_plat_failed:
> >> +init_core_failed:
> >> +    dev_set_drvdata(&pdev->dev, NULL);
> >> +    g_core = NULL;
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
> >> +{
> >> +    struct msm_vidc_core *core = NULL;
> >> +    int rc = 0;
> >> +
> >> +    if (!pdev) {
> >> +        d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
> >> +        return -EINVAL;
> >> +    } else if (!pdev->dev.parent) {
> >> +        d_vpr_e("%s: Failed to find a parent for %s\n",
> >> +            __func__, dev_name(&pdev->dev));
> >> +        return -ENODEV;
> >> +    }
> >> +
> >> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
> >> +
> >> +    core = dev_get_drvdata(pdev->dev.parent);
> >> +    if (!core) {
> >> +        d_vpr_e("%s: core not found in device %s",
> >> +            __func__, dev_name(pdev->dev.parent));
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    rc = msm_vidc_setup_context_bank(core, &pdev->dev);
> >> +    if (rc) {
> >> +        d_vpr_e("%s: Failed to probe context bank %s\n",
> >> +            __func__, dev_name(&pdev->dev));
> >> +        return rc;
> >> +    }
> >> +
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_probe(struct platform_device *pdev)
> >> +{
> >> +    if (!pdev) {
> >> +        d_vpr_e("%s: invalid params\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    /*
> >> +     * 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 (is_video_device(&pdev->dev))
> >> +        return msm_vidc_probe_video_device(pdev);
> >> +    else if (is_video_context_bank_device(&pdev->dev))
> >> +        return msm_vidc_probe_context_bank(pdev);
> >> +
> >> +    /* How did we end up here? */
> >> +    WARN_ON(1);
> >> +    return -EINVAL;
> >
> > No. Please don't hack around the driver infrastructure and register two
> > separate drivers. They can even come in two separate commits, simplifying
> > the review.
> >
> Sure, will remove the separate probe for context bank in next version.
> >> +}
> >> +
> >> +static int msm_vidc_pm_suspend(struct device *dev)
> >> +{
> >> +    int rc = 0;
> >> +    struct msm_vidc_core *core;
> >> +    enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
> >> +
> >> +    /*
> >> +     * Bail out if
> >> +     * - driver possibly not probed yet
> >> +     * - not the main device. We don't support power management on
> >> +     *   subdevices (e.g. context banks)
> >> +     */
> >> +    if (!dev || !dev->driver || !is_video_device(dev))
> >> +        return 0;
> >> +
> >> +    core = dev_get_drvdata(dev);
> >> +    if (!core) {
> >> +        d_vpr_e("%s: invalid core\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    core_lock(core, __func__);
> >> +    allow = msm_vidc_allow_pm_suspend(core);
> >> +
> >> +    if (allow == MSM_VIDC_IGNORE) {
> >> +        d_vpr_h("%s: pm already suspended\n", __func__);
> >> +        msm_vidc_change_core_sub_state(core, 0,
> >> CORE_SUBSTATE_PM_SUSPEND, __func__);
> >> +        rc = 0;
> >> +        goto unlock;
> >> +    } else if (allow != MSM_VIDC_ALLOW) {
> >> +        d_vpr_h("%s: pm suspend not allowed\n", __func__);
> >> +        rc = 0;
> >> +        goto unlock;
> >> +    }
> >> +
> >> +    rc = msm_vidc_suspend(core);
> >> +    if (rc == -EOPNOTSUPP)
> >> +        rc = 0;
> >> +    else if (rc)
> >> +        d_vpr_e("Failed to suspend: %d\n", rc);
> >> +    else
> >> +        msm_vidc_change_core_sub_state(core, 0,
> >> CORE_SUBSTATE_PM_SUSPEND, __func__);
> >> +
> >> +unlock:
> >> +    core_unlock(core, __func__);
> >> +    return rc;
> >> +}
> >> +
> >> +static int msm_vidc_pm_resume(struct device *dev)
> >> +{
> >> +    struct msm_vidc_core *core;
> >> +
> >> +    /*
> >> +     * Bail out if
> >> +     * - driver possibly not probed yet
> >> +     * - not the main device. We don't support power management on
> >> +     *   subdevices (e.g. context banks)
> >> +     */
> >> +    if (!dev || !dev->driver || !is_video_device(dev))
> >> +        return 0;
> >> +
> >> +    core = dev_get_drvdata(dev);
> >> +    if (!core) {
> >> +        d_vpr_e("%s: invalid core\n", __func__);
> >> +        return -EINVAL;
> >> +    }
> >> +
> >> +    /* remove PM suspend from core sub_state */
> >> +    core_lock(core, __func__);
> >> +    msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0,
> >> __func__);
> >> +    core_unlock(core, __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)
> >
> > No runtime PM?
> runtime PM is not added in this series, but we plan to add it at later
> point of time.
> >
> >> +};
> >> +
> >> +struct platform_driver msm_vidc_driver = {
> >> +    .probe = msm_vidc_probe,
> >> +    .remove = msm_vidc_remove,
> >> +    .driver = {
> >> +        .name = "msm_vidc_v4l2",
> >> +        .of_match_table = msm_vidc_dt_match,
> >> +        .pm = &msm_vidc_pm_ops,
> >> +    },
> >> +};
> >> +
> >> +module_platform_driver(msm_vidc_driver);
> >> +MODULE_LICENSE("GPL");
> >
> > Unfortunately, after taking a glance at first two patches, I have to stop.
> > It is nearly impossible to review it.
> >
> > Please start from the beginning, split the driver according to the logical
> > functions, not per-file. Ideally something should be compillable starting
> > from one of the first patches, if not the very first one. This would
> > guarantee that your patchset is structured logically.
> >
> > Please add DT bindings. New driver series should start from the bindings
> > anyway.
> >
> > Please drop your custom debugging wrappers. Use dev_info, dev_warn, dev_err
> > and dev_dbg instead.
> >
> > Please drop the custom multi-device-single-driver scheme. If there are
> > different kinds of devices, there should be different drivers.
> >
> > Please take a look around. If you are pushing your driver for kernel
> > inclusion, it should not stand out by the style and by the typical code
> > seuqences.
>
> Thanks a lot for all your comments, will take care of these in next version.



-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550
  2023-08-14 19:35     ` Dikshita Agarwal
@ 2023-08-14 21:17       ` Dmitry Baryshkov
  0 siblings, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-14 21:17 UTC (permalink / raw)
  To: Dikshita Agarwal
  Cc: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm

On Mon, 14 Aug 2023 at 22:36, Dikshita Agarwal
<quic_dikshita@quicinc.com> wrote:
>
>
>
> On 7/28/2023 7:43 PM, Dmitry Baryshkov wrote:
> > On 28/07/2023 16:23, Vikash Garodia wrote:
> >> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >>
> >> This implements all the capabilities supported by sm8550.
> >>
> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> >> ---
> >>   .../iris/platform/sm8550/inc/msm_vidc_sm8550.h     |   14 +
> >>   .../iris/platform/sm8550/src/msm_vidc_sm8550.c     | 1727
> >> ++++++++++++++++++++
> >>   2 files changed, 1741 insertions(+)
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> >>
> >> diff --git
> >> a/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> >> b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> >> new file mode 100644
> >> index 0000000..0a2f172
> >> --- /dev/null
> >> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/inc/msm_vidc_sm8550.h
> >> @@ -0,0 +1,14 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only */
> >> +/*
> >> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> >> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
> >> reserved.
> >> + */
> >> +
> >> +#ifndef _MSM_VIDC_SM8550_H_
> >> +#define _MSM_VIDC_SM8550_H_
> >> +
> >> +#include "msm_vidc_core.h"
> >> +
> >> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core);
> >> +
> >> +#endif // _MSM_VIDC_SM8550_H_
> >> diff --git
> >> a/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> >> b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> >> new file mode 100644
> >> index 0000000..2408556
> >> --- /dev/null
> >> +++ b/drivers/media/platform/qcom/iris/platform/sm8550/src/msm_vidc_sm8550.c
> >> @@ -0,0 +1,1727 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> >> + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights
> >> reserved.
> >> + */
> >> +
> >> +#include <dt-bindings/clock/qcom,sm8550-gcc.h>
> >> +#include <dt-bindings/clock/qcom,sm8450-videocc.h>
> >> +
> >> +#include "hfi_command.h"
> >> +#include "hfi_property.h"
> >> +#include "msm_vidc_control.h"
> >> +#include "msm_vidc_debug.h"
> >> +#include "msm_vidc_iris3.h"
> >> +#include "msm_vidc_sm8550.h"
> >> +#include "msm_vidc_platform.h"
> >> +
> >> +/* version: major[24:31], minor[16:23], revision[0:15] */
> >> +#define DRIVER_VERSION          0x04000000
> >> +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010
> >> +#define MAX_BASE_LAYER_PRIORITY_ID 63
> >> +#define MAX_OP_POINT            31
> >> +#define MAX_BITRATE             245000000
> >> +#define DEFAULT_BITRATE         20000000
> >> +#define MINIMUM_FPS             1
> >> +#define MAXIMUM_FPS             480
> >> +#define MAXIMUM_DEC_FPS         960
> >> +#define MAX_QP                  51
> >> +#define DEFAULT_QP              20
> >> +#define MAX_CONSTANT_QUALITY    100
> >> +#define MIN_SLICE_BYTE_SIZE     512
> >> +#define MAX_SLICE_BYTE_SIZE       \
> >> +    ((MAX_BITRATE) >> 3)
> >> +#define MAX_SLICE_MB_SIZE         \
> >> +    (((4096 + 15) >> 4) * ((2304 + 15) >> 4))
> >> +
> >> +#define ENC     MSM_VIDC_ENCODER
> >> +#define DEC     MSM_VIDC_DECODER
> >> +#define H264    MSM_VIDC_H264
> >> +#define HEVC    MSM_VIDC_HEVC
> >> +#define VP9     MSM_VIDC_VP9
> >
> > Another redefinition. Inline it.
> > >> +#define CODECS_ALL     (H264 | HEVC | VP9)
> >> +#define MAXIMUM_OVERRIDE_VP9_FPS 200
> >> +
> >> +static struct codec_info codec_data_sm8550[] = {
> >> +    {
> >> +        .v4l2_codec  = V4L2_PIX_FMT_H264,
> >> +        .vidc_codec  = MSM_VIDC_H264,
> >> +        .pixfmt_name = "AVC",
> >
> > Have you considered using existing code which enumerates formats? For
> > example, it is much better to refactor v4l_fill_fmtdesc() to allow getting
> > the description instead of adding your own names here.
> > Not to mention that printk supports %p4cc for printing fourcc values. I
> > hope you knew that.
> >
> Sure, will explore more on this.
> >> +    },
> >> +    {
> >> +        .v4l2_codec  = V4L2_PIX_FMT_HEVC,
> >> +        .vidc_codec  = MSM_VIDC_HEVC,
> >> +        .pixfmt_name = "HEVC",
> >> +    },
> >> +    {
> >> +        .v4l2_codec  = V4L2_PIX_FMT_VP9,
> >> +        .vidc_codec  = MSM_VIDC_VP9,
> >> +        .pixfmt_name = "VP9",
> >> +    },
> >> +};
> >> +
> >> +static struct color_format_info color_format_data_sm8550[] = {
> >> +    {
> >> +        .v4l2_color_format = V4L2_PIX_FMT_NV12,
> >> +        .vidc_color_format = MSM_VIDC_FMT_NV12,
> >> +        .pixfmt_name       = "NV12",
> >> +    },
> >> +    {
> >> +        .v4l2_color_format = V4L2_PIX_FMT_NV21,
> >> +        .vidc_color_format = MSM_VIDC_FMT_NV21,
> >> +        .pixfmt_name       = "NV21",
> >> +    },
> >> +    {
> >> +        .v4l2_color_format = V4L2_PIX_FMT_QC08C,
> >> +        .vidc_color_format = MSM_VIDC_FMT_NV12C,
> >> +        .pixfmt_name       = "NV12C",
> >> +    },
> >> +    {
> >> +        .v4l2_color_format = V4L2_PIX_FMT_QC10C,
> >> +        .vidc_color_format = MSM_VIDC_FMT_TP10C,
> >> +        .pixfmt_name       = "TP10C",
> >> +    },
> >> +    {
> >> +        .v4l2_color_format = V4L2_PIX_FMT_RGBA32,
> >> +        .vidc_color_format = MSM_VIDC_FMT_RGBA8888,
> >> +        .pixfmt_name       = "RGBA",
> >> +    },
> >> +};
> >> +
> >> +static struct color_primaries_info color_primaries_data_sm8550[] = {
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_DEFAULT,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_RESERVED,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_REC709,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT709,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_M,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_470_SYSTEM_BG,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE170M,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT601_525,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_SMPTE240M,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_ST240M,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_BT2020,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_BT2020,
> >> +    },
> >> +    {
> >> +        .v4l2_color_primaries  = V4L2_COLORSPACE_DCI_P3,
> >> +        .vidc_color_primaries  = MSM_VIDC_PRIMARIES_SMPTE_RP431_2,
> >> +    },
> >> +};
> >> +
> >> +static struct transfer_char_info transfer_char_data_sm8550[] = {
> >> +    {
> >> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_DEFAULT,
> >> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_RESERVED,
> >> +    },
> >> +    {
> >> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_709,
> >> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_BT709,
> >> +    },
> >> +    {
> >> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE240M,
> >> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST240M,
> >> +    },
> >> +    {
> >> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SRGB,
> >> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SRGB_SYCC,
> >> +    },
> >> +    {
> >> +        .v4l2_transfer_char  = V4L2_XFER_FUNC_SMPTE2084,
> >> +        .vidc_transfer_char  = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ,
> >> +    },
> >> +};
> >> +
> >> +static struct matrix_coeff_info matrix_coeff_data_sm8550[] = {
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_DEFAULT,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_RESERVED,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_709,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV709,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT709,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_XV601,
> >> +        .vidc_matrix_coeff  =
> >> MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_601,
> >> +        .vidc_matrix_coeff  =
> >> MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_SMPTE240M,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT,
> >> +    },
> >> +    {
> >> +        .v4l2_matrix_coeff  = V4L2_YCBCR_ENC_BT2020_CONST_LUM,
> >> +        .vidc_matrix_coeff  = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT,
> >> +    },
> >> +};
> >
> > Are you going to say that these tables are platform-specific instead of
> > being generic to the driver?
> >
> future platform can support new codec and that will require new color
> primaries. So, yes these can differ for different platforms.

Please do not try to implement support for not-yet-existing hardware.
Move this table into the generic code until you have a real cause of
disagreement about matrix coefficients. Otherwise the table can simply
be expanded to add new color primaries support.

> >> +
> >> +static struct msm_platform_core_capability core_data_sm8550[] = {
> >> +    /* {type, value} */
> >> +    {ENC_CODECS, H264 | HEVC},
> >> +    {DEC_CODECS, H264 | HEVC | VP9},
> >> +    {MAX_SESSION_COUNT, 16},
> >> +    {MAX_NUM_720P_SESSIONS, 16},
> >> +    {MAX_NUM_1080P_SESSIONS, 16},
> >> +    {MAX_NUM_4K_SESSIONS, 8},
> >> +    {MAX_NUM_8K_SESSIONS, 2},
> >> +    {MAX_RT_MBPF, 174080},    /* (8192x4352)/256 + (4096x2176)/256*/
> >> +    {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */
> >> +    {MAX_MBPS, 7833600},    /* max_load
> >> +                 * 7680x4320@60fps or 3840x2176@240fps
> >> +                 * which is greater than 4096x2176@120fps,
> >> +                 * 8192x4320@48fps
> >> +                 */
> >> +    {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */
> >> +    {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */
> >> +    {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */
> >> +    {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */
> >> +    {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */
> >> +    {MAX_ENH_LAYER_COUNT, 5},
> >> +    {NUM_VPP_PIPE, 4},
> >> +    {SW_PC, 1},
> >> +    {FW_UNLOAD, 0},
> >> +    {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */
> >> +    {SW_PC_DELAY,         SW_PC_DELAY_VALUE        }, /* 1500 ms
> >> (>HW_RESPONSE_TIMEOUT)*/
> >> +    {FW_UNLOAD_DELAY,     FW_UNLOAD_DELAY_VALUE    }, /* 3000 ms
> >> (>SW_PC_DELAY)*/
> >> +    {DCVS, 1},
> >> +    {DECODE_BATCH, 1},
> >> +    {DECODE_BATCH_TIMEOUT, 200},
> >> +    {STATS_TIMEOUT_MS, 2000},
> >> +    {NON_FATAL_FAULTS, 1},
> >> +    {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING},
> >
> > Unless there is a good reason, please change this to be a proper data
> > structure instead of being a type-value array. With the T-V it is
> > impossible to notice if the value is missing or duplicated. This comment
> > also applies to the next 'capability' array.
> >
> Core has set of caps. All caps might not be supported for all the hardware.
> So it's quite valid to miss a cap entry if its not applicable for that
> hardware.
> subsequently with caps as enum, it will become easy to copy these caps from
> platform to core.

... and it becomes harder to check them (e.g. for duplicates). Please
use nested structures and omit values for undefined capabilities.

>
> please check msm_vidc_init_core_caps API in [1]
>
> [1]
> https://patchwork.linuxtv.org/project/linux-media/patch/1690550624-14642-11-git-send-email-quic_vgarodia@quicinc.com/

In that patch I see that capabilities are enumerated as an array.
Which is already much better than plain tag-value data structure. But
please drop both implementations and use existing C language
constructions.

>
> >> +};
> >> +
> >> +static struct msm_platform_inst_capability instance_cap_data_sm8550[] = {
> >> +    /* {cap, domain, codec,
> >> +     *      min, max, step_or_mask, value,
> >> +     *      v4l2_id,
> >> +     *      hfi_id,
> >> +     *      flags}
> >> +     */
> >> +    {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920},
> >> +
> >> +    {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920},
> >> +
> >> +    {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920},
> >> +
> >> +    {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920},
> >> +
> >> +    {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920},
> >> +
> >> +    {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920},
> >> +
> >> +    {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080},
> >> +
> >> +    {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080},
> >> +
> >> +    {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080},
> >> +
> >> +    {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080},
> >> +
> >> +    {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080},
> >> +
> >> +    {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080},
> >> +
> >> +    {PIX_FMTS, ENC | DEC, H264,
> >> +        MSM_VIDC_FMT_NV12,
> >> +        MSM_VIDC_FMT_NV12C,
> >> +        MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C,
> >> +        MSM_VIDC_FMT_NV12C},
> >> +
> >> +    {PIX_FMTS, ENC | DEC, HEVC | VP9,
> >> +        MSM_VIDC_FMT_NV12,
> >> +        MSM_VIDC_FMT_TP10C,
> >> +        MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C |
> >> +        MSM_VIDC_FMT_TP10C,
> >> +        MSM_VIDC_FMT_NV12C},
> >> +
> >> +    {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4,
> >> +        V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
> >> +        0,
> >> +        CAP_FLAG_VOLATILE},
> >> +
> >> +    {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL,
> >> +        0, 64, 1, 4,
> >> +        V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
> >> +        HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE},
> >> +
> >> +    /* (8192 * 4320) / 256 */
> >> +    {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240},
> >> +
> >> +    {MBPF, ENC, HEVC, 36, 138240, 1, 138240},
> >> +
> >> +    {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240},
> >> +
> >> +    /* (4096 * 2304) / 256 */
> >> +    {MBPF, DEC, VP9, 36, 36864, 1, 36864},
> >> +
> >> +    /* (4096 * 2304) / 256 */
> >> +    {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864},
> >> +
> >> +    /* Batch Mode Decode */
> >> +    /* TODO: update with new values based on updated voltage corner */
> >> +    {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816},
> >> +
> >> +    /* (4096 * 2304) / 256 */
> >> +    {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120},
> >> +
> >> +    {FRAME_RATE, ENC | DEC, CODECS_ALL,
> >> +        (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
> >> +        1, (DEFAULT_FPS << 16),
> >> +        0,
> >> +        HFI_PROP_FRAME_RATE,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {OPERATING_RATE, ENC | DEC, CODECS_ALL,
> >> +        (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16),
> >> +        1, (DEFAULT_FPS << 16)},
> >> +
> >> +    {INPUT_RATE, ENC | DEC, CODECS_ALL,
> >> +        (MINIMUM_FPS << 16), INT_MAX,
> >> +        1, (DEFAULT_FPS << 16)},
> >> +
> >> +    {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL,
> >> +        (MINIMUM_FPS << 16), INT_MAX,
> >> +        1, (DEFAULT_FPS << 16)},
> >> +
> >> +    {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8},
> >> +
> >> +    {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25},
> >> +
> >> +    {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25},
> >> +
> >> +    {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60},
> >> +
> >> +    {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675},
> >> +
> >> +    {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200},
> >> +
> >> +    {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320},
> >> +
> >> +    {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200},
> >> +
> >> +    {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583},
> >> +
> >> +    {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405},
> >> +
> >> +    {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234},
> >> +
> >> +    {HFLIP, ENC, CODECS_ALL,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_HFLIP,
> >> +        HFI_PROP_FLIP,
> >> +        CAP_FLAG_OUTPUT_PORT |
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {VFLIP, ENC, CODECS_ALL,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_VFLIP,
> >> +        HFI_PROP_FLIP,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +        CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {ROTATION, ENC, CODECS_ALL,
> >> +        0, 270, 90, 0,
> >> +        V4L2_CID_ROTATE,
> >> +        HFI_PROP_ROTATION,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {HEADER_MODE, ENC, CODECS_ALL,
> >> +        V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
> >> +        V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
> >> +        BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
> >> +        V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEADER_MODE,
> >> +        HFI_PROP_SEQ_HEADER_MODE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR},
> >> +
> >> +    {WITHOUT_STARTCODE, ENC, CODECS_ALL,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
> >> +        HFI_PROP_NAL_LENGTH_FIELD,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {NAL_LENGTH_FIELD, ENC, CODECS_ALL,
> >> +        V4L2_MPEG_VIDEO_HEVC_SIZE_0,
> >> +        V4L2_MPEG_VIDEO_HEVC_SIZE_4,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4),
> >> +        V4L2_MPEG_VIDEO_HEVC_SIZE_0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
> >> +        HFI_PROP_NAL_LENGTH_FIELD,
> >> +        CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    /* TODO: Firmware introduced enumeration type for this
> >> +     * with and without seq header.
> >> +     */
> >> +    {REQUEST_I_FRAME, ENC, H264 | HEVC,
> >> +        0, 0, 0, 0,
> >> +        V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
> >> +        HFI_PROP_REQUEST_SYNC_FRAME,
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    /* Enc: Keeping CABAC and CAVLC as same bitrate.
> >> +     * Dec: there's no use of Bitrate cap
> >> +     */
> >> +    {BIT_RATE, ENC, H264 | HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_BITRATE,
> >> +        HFI_PROP_TOTAL_BITRATE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +        CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {BITRATE_MODE, ENC, H264,
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
> >> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
> >> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> >> +        V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
> >> +        HFI_PROP_RATE_CONTROL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {BITRATE_MODE, ENC, HEVC,
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_CQ,
> >> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
> >> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
> >> +        BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ),
> >> +        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
> >> +        V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
> >> +        HFI_PROP_RATE_CONTROL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0,
> >> +        160000000, 1, 160000000},
> >> +
> >> +    {CAVLC_MAX_BITRATE, ENC, H264, 0,
> >> +        220000000, 1, 220000000},
> >> +
> >> +    {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0,
> >> +        245000000, 1, 245000000},
> >> +
> >> +    {NUM_COMV, DEC, CODECS_ALL,
> >> +        0, INT_MAX, 1, 0},
> >> +
> >> +    {LOSSLESS, ENC, HEVC,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU},
> >> +
> >> +    {FRAME_SKIP_MODE, ENC, H264 | HEVC,
> >> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
> >> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
> >> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
> >> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) |
> >> +        BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
> >> +        V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
> >> +        V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {FRAME_RC_ENABLE, ENC, H264 | HEVC,
> >> +        0, 1, 1, 1,
> >> +        V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE},
> >> +
> >> +    {CONSTANT_QUALITY, ENC, HEVC,
> >> +        1, MAX_CONSTANT_QUALITY, 1, 90,
> >> +        V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY,
> >> +        HFI_PROP_CONSTANT_QUALITY,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +        CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {GOP_SIZE, ENC, CODECS_ALL,
> >> +        0, INT_MAX, 1, 2 * DEFAULT_FPS - 1,
> >> +        V4L2_CID_MPEG_VIDEO_GOP_SIZE,
> >> +        HFI_PROP_MAX_GOP_FRAMES,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +        CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {GOP_CLOSURE, ENC, H264 | HEVC,
> >> +        0, 1, 1, 1,
> >> +        V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
> >> +        0},
> >> +
> >> +    {B_FRAME, ENC, H264 | HEVC,
> >> +        0, 7, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_B_FRAMES,
> >> +        HFI_PROP_MAX_B_FRAMES,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {LTR_COUNT, ENC, H264 | HEVC,
> >> +        0, MAX_LTR_FRAME_COUNT_2, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_LTR_COUNT,
> >> +        HFI_PROP_LTR_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {USE_LTR, ENC, H264 | HEVC,
> >> +        0,
> >> +        ((1 << MAX_LTR_FRAME_COUNT_2) - 1),
> >> +        0, 0,
> >> +        V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES,
> >> +        HFI_PROP_LTR_USE,
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {MARK_LTR, ENC, H264 | HEVC,
> >> +        INVALID_DEFAULT_MARK_OR_USE_LTR,
> >> +        (MAX_LTR_FRAME_COUNT_2 - 1),
> >> +        1, INVALID_DEFAULT_MARK_OR_USE_LTR,
> >> +        V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX,
> >> +        HFI_PROP_LTR_MARK,
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {BASELAYER_PRIORITY, ENC, H264,
> >> +        0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID,
> >> +        HFI_PROP_BASELAYER_PRIORITYID,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {IR_TYPE, ENC, H264 | HEVC,
> >> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
> >> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
> >> +        BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) |
> >> +        BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC),
> >> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
> >> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {IR_PERIOD, ENC, H264 | HEVC,
> >> +        0, INT_MAX, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
> >> +        0,
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT |
> >> +        CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {AU_DELIMITER, ENC, H264 | HEVC,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
> >> +        HFI_PROP_AUD,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {MIN_QUALITY, ENC, H264 | HEVC,
> >> +        0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY,
> >> +        0,
> >> +        HFI_PROP_MAINTAIN_MIN_QUALITY,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {VBV_DELAY, ENC, H264 | HEVC,
> >> +        200, 300, 100, 300,
> >> +        V4L2_CID_MPEG_VIDEO_VBV_DELAY,
> >> +        HFI_PROP_VBV_DELAY,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {PEAK_BITRATE, ENC, H264 | HEVC,
> >> +        /* default peak bitrate is 10% larger than avg bitrate */
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
> >> +        HFI_PROP_TOTAL_PEAK_BITRATE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {MIN_FRAME_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> >> +        V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
> >> +        HFI_PROP_MIN_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {MIN_FRAME_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
> >> +        HFI_PROP_MIN_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {I_FRAME_MIN_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> >> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP},
> >> +
> >> +    {I_FRAME_MIN_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP},
> >> +
> >> +    {P_FRAME_MIN_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> >> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP},
> >> +
> >> +    {P_FRAME_MIN_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP},
> >> +
> >> +    {B_FRAME_MIN_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT,
> >> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP},
> >> +
> >> +    {B_FRAME_MIN_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP},
> >> +
> >> +    {MAX_FRAME_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
> >> +        HFI_PROP_MAX_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {MAX_FRAME_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
> >> +        HFI_PROP_MAX_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {I_FRAME_MAX_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP},
> >> +
> >> +    {I_FRAME_MAX_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP},
> >> +
> >> +    {P_FRAME_MAX_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP},
> >> +
> >> +    {P_FRAME_MAX_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP},
> >> +
> >> +    {B_FRAME_MAX_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP},
> >> +
> >> +    {B_FRAME_MAX_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, MAX_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP},
> >> +
> >> +    {I_FRAME_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {I_FRAME_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {P_FRAME_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {P_FRAME_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {B_FRAME_QP, ENC, HEVC,
> >> +        MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {B_FRAME_QP, ENC, H264,
> >> +        MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP,
> >> +        V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
> >> +        HFI_PROP_QP_PACKED,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {LAYER_TYPE, ENC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
> >> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P),
> >> +        V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
> >> +        HFI_PROP_LAYER_ENCODING_TYPE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LAYER_TYPE, ENC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
> >> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P),
> >> +        V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
> >> +        HFI_PROP_LAYER_ENCODING_TYPE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LAYER_ENABLE, ENC, H264,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
> >> +        HFI_PROP_LAYER_ENCODING_TYPE,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {LAYER_ENABLE, ENC, HEVC,
> >> +        0, 1, 1, 0,
> >> +        0,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {ENH_LAYER_COUNT, ENC, HEVC,
> >> +        0, 5, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
> >> +        HFI_PROP_LAYER_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {ENH_LAYER_COUNT, ENC, H264,
> >> +        0, 5, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
> >> +        HFI_PROP_LAYER_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L0_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
> >> +        HFI_PROP_BITRATE_LAYER1,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L0_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
> >> +        HFI_PROP_BITRATE_LAYER1,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L1_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
> >> +        HFI_PROP_BITRATE_LAYER2,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L1_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
> >> +        HFI_PROP_BITRATE_LAYER2,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L2_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
> >> +        HFI_PROP_BITRATE_LAYER3,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L2_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
> >> +        HFI_PROP_BITRATE_LAYER3,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L3_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
> >> +        HFI_PROP_BITRATE_LAYER4,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +    {L3_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
> >> +        HFI_PROP_BITRATE_LAYER4,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L4_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
> >> +        HFI_PROP_BITRATE_LAYER5,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L4_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
> >> +        HFI_PROP_BITRATE_LAYER5,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L5_BR, ENC, H264,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
> >> +        HFI_PROP_BITRATE_LAYER6,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {L5_BR, ENC, HEVC,
> >> +        1, MAX_BITRATE, 1, DEFAULT_BITRATE,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
> >> +        HFI_PROP_BITRATE_LAYER6,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
> >> +            CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {ENTROPY_MODE, ENC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> >> +        V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
> >> +        HFI_PROP_CABAC_SESSION,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {ENTROPY_MODE, DEC, H264 | HEVC | VP9,
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
> >> +        V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
> >> +        0,
> >> +        HFI_PROP_CABAC_SESSION},
> >> +
> >> +    {PROFILE, ENC | DEC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
> >> +        V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH),
> >> +        V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> >> +        V4L2_CID_MPEG_VIDEO_H264_PROFILE,
> >> +        HFI_PROP_PROFILE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {PROFILE, ENC | DEC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> >> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10),
> >> +        V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> >> +        HFI_PROP_PROFILE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {PROFILE, DEC, VP9,
> >> +        V4L2_MPEG_VIDEO_VP9_PROFILE_0,
> >> +        V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2),
> >> +        V4L2_MPEG_VIDEO_VP9_PROFILE_0,
> >> +        V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
> >> +        HFI_PROP_PROFILE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LEVEL, ENC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0),
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_5_0,
> >> +        V4L2_CID_MPEG_VIDEO_H264_LEVEL,
> >> +        HFI_PROP_LEVEL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LEVEL, ENC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_5,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> >> +        HFI_PROP_LEVEL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LEVEL, DEC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2),
> >> +        V4L2_MPEG_VIDEO_H264_LEVEL_6_1,
> >> +        V4L2_CID_MPEG_VIDEO_H264_LEVEL,
> >> +        HFI_PROP_LEVEL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LEVEL, DEC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2),
> >> +        V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> >> +        HFI_PROP_LEVEL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LEVEL, DEC, VP9,
> >> +        V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
> >> +        V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) |
> >> +        BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0),
> >> +        V4L2_MPEG_VIDEO_VP9_LEVEL_6_0,
> >> +        V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
> >> +        HFI_PROP_LEVEL,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {HEVC_TIER, ENC | DEC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
> >> +        V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH),
> >> +        V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_TIER,
> >> +        HFI_PROP_TIER,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LF_MODE, ENC, H264,
> >> +        V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
> >> +        DB_H264_DISABLE_SLICE_BOUNDARY,
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
> >> +        BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
> >> +        BIT(DB_H264_DISABLE_SLICE_BOUNDARY),
> >> +        V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
> >> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
> >> +        HFI_PROP_DEBLOCKING_MODE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LF_MODE, ENC, HEVC,
> >> +        V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
> >> +        DB_HEVC_DISABLE_SLICE_BOUNDARY,
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) |
> >> +        BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) |
> >> +        BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY),
> >> +        V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
> >> +        HFI_PROP_DEBLOCKING_MODE,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {LF_ALPHA, ENC, H264,
> >> +        -6, 6, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA},
> >> +
> >> +    {LF_ALPHA, ENC, HEVC,
> >> +        -6, 6, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2},
> >> +
> >> +    {LF_BETA, ENC, H264,
> >> +        -6, 6, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA},
> >> +
> >> +    {LF_BETA, ENC, HEVC,
> >> +        -6, 6, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2},
> >> +
> >> +    {SLICE_MODE, ENC, H264 | HEVC,
> >> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
> >> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
> >> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
> >> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) |
> >> +        BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES),
> >> +        V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
> >> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU},
> >> +
> >> +    {SLICE_MAX_BYTES, ENC, H264 | HEVC,
> >> +        MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE,
> >> +        1, MIN_SLICE_BYTE_SIZE,
> >> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
> >> +        HFI_PROP_MULTI_SLICE_BYTES_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {SLICE_MAX_MB, ENC, H264 | HEVC,
> >> +        1, MAX_SLICE_MB_SIZE, 1, 1,
> >> +        V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
> >> +        HFI_PROP_MULTI_SLICE_MB_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {MB_RC, ENC, H264 | HEVC,
> >> +        0, 1, 1, 1,
> >> +        V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {TRANSFORM_8X8, ENC, H264,
> >> +        0, 1, 1, 1,
> >> +        V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
> >> +        HFI_PROP_8X8_TRANSFORM,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
> >> +        MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET,
> >> +        1, MAX_CHROMA_QP_OFFSET,
> >> +        V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
> >> +        HFI_PROP_CHROMA_QP_OFFSET,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
> >> +        HFI_PROP_DECODE_ORDER_OUTPUT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
> >> +        0, 1, 1, 0,
> >> +        V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
> >> +        HFI_PROP_DECODE_ORDER_OUTPUT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
> >> +        0, 1, 1, 0,
> >> +        0,
> >> +        HFI_PROP_DECODE_ORDER_OUTPUT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> >> +        DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
> >> +        1, DEFAULT_MAX_HOST_BUF_COUNT,
> >> +        0,
> >> +        HFI_PROP_BUFFER_HOST_MAX_COUNT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> >> +        DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT,
> >> +        1, DEFAULT_MAX_HOST_BUF_COUNT,
> >> +        0,
> >> +        HFI_PROP_BUFFER_HOST_MAX_COUNT,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +
> >> +    {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1,
> >> +        DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
> >> +        V4L2_CID_MPEG_VIDEO_MUTE_YUV,
> >> +        HFI_PROP_CONCEAL_COLOR_8BIT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1,
> >> +        DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
> >> +        V4L2_CID_MPEG_VIDEO_MUTE_YUV,
> >> +        HFI_PROP_CONCEAL_COLOR_10BIT,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {STAGE, DEC | ENC, CODECS_ALL,
> >> +        MSM_VIDC_STAGE_1,
> >> +        MSM_VIDC_STAGE_2, 1,
> >> +        MSM_VIDC_STAGE_2,
> >> +        0,
> >> +        HFI_PROP_STAGE},
> >> +
> >> +    {PIPE, DEC | ENC, CODECS_ALL,
> >> +        MSM_VIDC_PIPE_1,
> >> +        MSM_VIDC_PIPE_4, 1,
> >> +        MSM_VIDC_PIPE_4,
> >> +        0,
> >> +        HFI_PROP_PIPE},
> >> +
> >> +    {POC, DEC, H264, 0, 2, 1, 1,
> >> +        0,
> >> +        HFI_PROP_PIC_ORDER_CNT_TYPE},
> >> +
> >> +    {QUALITY_MODE, ENC, CODECS_ALL,
> >> +        MSM_VIDC_MAX_QUALITY_MODE,
> >> +        MSM_VIDC_POWER_SAVE_MODE, 1,
> >> +        MSM_VIDC_POWER_SAVE_MODE},
> >> +
> >> +    {CODED_FRAMES, DEC, H264 | HEVC,
> >> +        CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE,
> >> +        1, CODED_FRAMES_PROGRESSIVE,
> >> +        0,
> >> +        HFI_PROP_CODED_FRAMES},
> >> +
> >> +    {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8,
> >> +        0,
> >> +        HFI_PROP_LUMA_CHROMA_BIT_DEPTH},
> >> +
> >> +    {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0,
> >> +        0},
> >> +
> >> +    {DEFAULT_HEADER, DEC, CODECS_ALL,
> >> +        0, 1, 1, 0,
> >> +        0,
> >> +        HFI_PROP_DEC_DEFAULT_HEADER},
> >> +
> >> +    {RAP_FRAME, DEC, CODECS_ALL,
> >> +        0, 1, 1, 1,
> >> +        0,
> >> +        HFI_PROP_DEC_START_FROM_RAP_FRAME,
> >> +        CAP_FLAG_INPUT_PORT},
> >> +
> >> +    {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL,
> >> +        0, 1, 1, 1,
> >> +        0,
> >> +        HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME,
> >> +        CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED},
> >> +
> >> +    {ALL_INTRA, ENC, H264 | HEVC,
> >> +        0, 1, 1, 0,
> >> +        0,
> >> +        0,
> >> +        CAP_FLAG_OUTPUT_PORT},
> >> +};
> >> +
> >> +static struct msm_platform_inst_cap_dependency
> >> instance_cap_dependency_data_sm8550[] = {
> >> +    /* {cap, domain, codec,
> >> +     *      children,
> >> +     *      adjust, set}
> >> +     */
> >> +
> >> +    {PIX_FMTS, ENC, H264,
> >> +        {IR_PERIOD}},
> >> +
> >> +    {PIX_FMTS, ENC, HEVC,
> >> +        {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP,
> >> +            B_FRAME_QP, MIN_QUALITY, IR_PERIOD, LTR_COUNT}},
> >> +
> >> +    {PIX_FMTS, DEC, HEVC,
> >> +        {PROFILE}},
> >> +
> >> +    {FRAME_RATE, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_q16},
> >> +
> >> +    {HFLIP, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_flip},
> >> +
> >> +    {VFLIP, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_flip},
> >> +
> >> +    {ROTATION, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_rotation},
> >> +
> >> +    {HEADER_MODE, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_header_mode},
> >> +
> >> +    {WITHOUT_STARTCODE, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_nal_length},
> >> +
> >> +    {REQUEST_I_FRAME, ENC, H264 | HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_req_sync_frame},
> >> +
> >> +    {BIT_RATE, ENC, H264,
> >> +        {PEAK_BITRATE, L0_BR},
> >> +        msm_vidc_adjust_bitrate,
> >> +        msm_vidc_set_bitrate},
> >> +
> >> +    {BIT_RATE, ENC, HEVC,
> >> +        {PEAK_BITRATE, L0_BR},
> >> +        msm_vidc_adjust_bitrate,
> >> +        msm_vidc_set_bitrate},
> >> +
> >> +    {BITRATE_MODE, ENC, H264,
> >> +        {LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
> >> +            B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE,
> >> +            MIN_QUALITY, VBV_DELAY,
> >> +            PEAK_BITRATE, SLICE_MODE},
> >> +        msm_vidc_adjust_bitrate_mode,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {BITRATE_MODE, ENC, HEVC,
> >> +        {LTR_COUNT, IR_PERIOD, I_FRAME_QP, P_FRAME_QP,
> >> +            B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT,
> >> +            BIT_RATE, MIN_QUALITY, VBV_DELAY,
> >> +            PEAK_BITRATE, SLICE_MODE},
> >> +        msm_vidc_adjust_bitrate_mode,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {CONSTANT_QUALITY, ENC, HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_constant_quality},
> >> +
> >> +    {GOP_SIZE, ENC, CODECS_ALL,
> >> +        {ALL_INTRA},
> >> +        msm_vidc_adjust_gop_size,
> >> +        msm_vidc_set_gop_size},
> >> +
> >> +    {B_FRAME, ENC, H264 | HEVC,
> >> +        {ALL_INTRA},
> >> +        msm_vidc_adjust_b_frame,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {LTR_COUNT, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_ltr_count,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {USE_LTR, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_use_ltr,
> >> +        msm_vidc_set_use_and_mark_ltr},
> >> +
> >> +    {MARK_LTR, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_mark_ltr,
> >> +        msm_vidc_set_use_and_mark_ltr},
> >> +
> >> +    {IR_PERIOD, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_ir_period,
> >> +        msm_vidc_set_ir_period},
> >> +
> >> +    {AU_DELIMITER, ENC, H264 | HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {MIN_QUALITY, ENC, H264,
> >> +        {0},
> >> +        msm_vidc_adjust_min_quality,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {MIN_QUALITY, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_min_quality,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {VBV_DELAY, ENC, H264 | HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_cbr_related_properties},
> >> +
> >> +    {PEAK_BITRATE, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_peak_bitrate,
> >> +        msm_vidc_set_cbr_related_properties},
> >> +
> >> +    {MIN_FRAME_QP, ENC, H264,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_min_qp},
> >> +
> >> +    {MIN_FRAME_QP, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_hevc_min_qp,
> >> +        msm_vidc_set_min_qp},
> >> +
> >> +    {MAX_FRAME_QP, ENC, H264,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_max_qp},
> >> +
> >> +    {MAX_FRAME_QP, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_hevc_max_qp,
> >> +        msm_vidc_set_max_qp},
> >> +
> >> +    {I_FRAME_QP, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_hevc_i_frame_qp,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {I_FRAME_QP, ENC, H264,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {P_FRAME_QP, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_hevc_p_frame_qp,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {P_FRAME_QP, ENC, H264,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {B_FRAME_QP, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_hevc_b_frame_qp,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {B_FRAME_QP, ENC, H264,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_frame_qp},
> >> +
> >> +    {LAYER_TYPE, ENC, H264 | HEVC,
> >> +        {LTR_COUNT}},
> >> +
> >> +    {LAYER_ENABLE, ENC, H264 | HEVC,
> >> +        {0}},
> >> +
> >> +    {ENH_LAYER_COUNT, ENC, H264 | HEVC,
> >> +        {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE,
> >> +            LTR_COUNT},
> >> +        msm_vidc_adjust_layer_count,
> >> +        msm_vidc_set_layer_count_and_type},
> >> +
> >> +    {L0_BR, ENC, H264 | HEVC,
> >> +        {L1_BR},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {L1_BR, ENC, H264 | HEVC,
> >> +        {L2_BR},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {L2_BR, ENC, H264 | HEVC,
> >> +        {L3_BR},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {L3_BR, ENC, H264 | HEVC,
> >> +        {L4_BR},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {L4_BR, ENC, H264 | HEVC,
> >> +        {L5_BR},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {L5_BR, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_layer_bitrate,
> >> +        msm_vidc_set_layer_bitrate},
> >> +
> >> +    {ENTROPY_MODE, ENC, H264,
> >> +        {BIT_RATE},
> >> +        msm_vidc_adjust_entropy_mode,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {PROFILE, ENC, H264,
> >> +        {ENTROPY_MODE, TRANSFORM_8X8},
> >> +        NULL,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {PROFILE, DEC, H264,
> >> +        {ENTROPY_MODE},
> >> +        NULL,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {PROFILE, ENC | DEC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_profile,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {PROFILE, DEC, VP9,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {LEVEL, DEC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {LEVEL, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_level},
> >> +
> >> +    {HEVC_TIER, ENC | DEC, HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32_enum},
> >> +
> >> +    {LF_MODE, ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_deblock_mode},
> >> +
> >> +    {SLICE_MODE, ENC, H264 | HEVC,
> >> +        {STAGE},
> >> +        msm_vidc_adjust_slice_count,
> >> +        msm_vidc_set_slice_count},
> >> +
> >> +    {TRANSFORM_8X8, ENC, H264,
> >> +        {0},
> >> +        msm_vidc_adjust_transform_8x8,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {CHROMA_QP_INDEX_OFFSET, ENC, HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_chroma_qp_index_offset,
> >> +        msm_vidc_set_chroma_qp_index_offset},
> >> +
> >> +    {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9,
> >> +        {OUTPUT_ORDER},
> >> +        NULL,
> >> +        NULL},
> >> +
> >> +    {DISPLAY_DELAY, DEC, H264 | HEVC | VP9,
> >> +        {OUTPUT_ORDER},
> >> +        NULL,
> >> +        NULL},
> >> +
> >> +    {OUTPUT_ORDER, DEC, H264 | HEVC | VP9,
> >> +        {0},
> >> +        msm_vidc_adjust_output_order,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> >> +        {0},
> >> +        msm_vidc_adjust_input_buf_host_max_count,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_input_buf_host_max_count,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL,
> >> +        {0},
> >> +        msm_vidc_adjust_output_buf_host_max_count,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC,
> >> +        {0},
> >> +        msm_vidc_adjust_output_buf_host_max_count,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32_packed},
> >> +
> >> +    {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32_packed},
> >> +
> >> +    {STAGE, ENC | DEC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_stage},
> >> +
> >> +    {STAGE, ENC, H264 | HEVC,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_stage},
> >> +
> >> +    {STAGE, DEC, H264 | HEVC | VP9,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_stage},
> >> +
> >> +    {PIPE, DEC | ENC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_pipe},
> >> +
> >> +    {RAP_FRAME, DEC, CODECS_ALL,
> >> +        {0},
> >> +        NULL,
> >> +        msm_vidc_set_u32},
> >> +
> >> +    {ALL_INTRA, ENC, H264 | HEVC,
> >> +        {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE},
> >> +        msm_vidc_adjust_all_intra,
> >> +        NULL},
> >> +};
> >> +
> >> +/* Default UBWC config for LPDDR5 */
> >> +static struct msm_vidc_ubwc_config_data ubwc_config_sm8550[] = {
> >> +    UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1),
> >> +};
> >> +
> >> +static struct msm_vidc_format_capability format_data_sm8550 = {
> >> +    .codec_info = codec_data_sm8550,
> >> +    .codec_info_size = ARRAY_SIZE(codec_data_sm8550),
> >> +    .color_format_info = color_format_data_sm8550,
> >> +    .color_format_info_size = ARRAY_SIZE(color_format_data_sm8550),
> >> +    .color_prim_info = color_primaries_data_sm8550,
> >> +    .color_prim_info_size = ARRAY_SIZE(color_primaries_data_sm8550),
> >> +    .transfer_char_info = transfer_char_data_sm8550,
> >> +    .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_sm8550),
> >> +    .matrix_coeff_info = matrix_coeff_data_sm8550,
> >> +    .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_sm8550),
> >> +};
> >> +
> >> +/* name, min_kbps, max_kbps */
> >> +static const struct bw_table sm8550_bw_table[] = {
> >> +    { "venus-cnoc",  1000, 1000     },
> >> +    { "venus-ddr",   1000, 15000000 },
> >
> > We have OPP tables for that. There is no need to limit the min/max, just
> > put it to OPP.
> >
> This table is used to vote for min and max bus bandwidth.
> for some test vector with bad picture order count, ref count can be huge,
> so DPB needs to be filled with high number of reference frames to process
> current frames, this needs faster frame processing so to address such
> cases, driver vote for max bus bandwidth.
> for some cases, when system is in suspend state, there might be some
> residual transitions happening for which driver needs to vote for min
> frequency during suspend state.

So? This can all be handled as a code handling OPP tables. I'm not
judging your voting code. I'm asking you to drop custom table and use
existing kernel mechanism for defining frequency / bandwidth tables.

> >> +};
> >> +
> >> +/* name */
> >> +static const struct pd_table sm8550_pd_table[] = {
> >> +    { "iris-ctl" },
> >> +    { "vcodec"   },
> >> +};
> >> +
> >> +/* name */
> >> +static const char * const sm8550_opp_table[] = { "mx", "mmcx", NULL };
> >> +
> >> +/* name, clock id, scaling */
> >> +static const struct clk_table sm8550_clk_table[] = {
> >> +    { "gcc_video_axi0",         GCC_VIDEO_AXI0_CLK,     0 },
> >> +    { "core_clk",               VIDEO_CC_MVS0C_CLK,     0 },
> >> +    { "vcodec_clk",             VIDEO_CC_MVS0_CLK,      1 },
> >> +};
> >
> > This strucuture looks like a perfect candidate to be replaced by
> > devm_clk_bulk_get_all().
> >
> Nice suggestion, will explore this.
> >> +
> >> +/* name, exclusive_release */
> >> +static const struct clk_rst_table sm8550_clk_reset_table[] = {
> >> +    { "video_axi_reset",        0  },
> >
> > Can we assume that resets are generic at least?
> >
> reset clocks can change for different hardware.

They can. But do they change for existing hardware?

> >> +};
> >> +
> >> +/* name, start, size, secure, dma_coherant, region, dma_mask */
> >> +const struct context_bank_table sm8550_context_bank_table[] = {
> >> +    {"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1,
> >> MSM_VIDC_NON_SECURE, 0xe0000000 - 1},
> >> +    {"qcom,vidc,cb-sec-non-pxl",   0x01000000, 0x24800000, 1, 0,
> >> MSM_VIDC_SECURE_NONPIXEL,  0 },
> >
> > Aren't these a properties of subdevices? If so, why are you putting them here?
> >
> Will remove these in next version.
> >> +};
> >> +
> >> +/* freq */
> >> +static struct freq_table sm8550_freq_table[] = {
> >> +    {533333333}, {444000000}, {366000000}, {338000000}, {240000000}
> >
> > OPP table contents.
> >
> we are using this freq table at multiple places apart from voting like
> - setting freq to turbo for few use cases
> - limiting the freq to NOM
> - changing the frequency levels based on DCVS
> hence this table is need.

And it doesn't stop it from being encoded as OPP table. We have
devfreq for DCVS, and OPP has a notion of turbo / nominal values.

> >> +};
> >> +
> >> +/* register, value, mask */
> >> +static const struct reg_preset_table sm8550_reg_preset_table[] = {
> >> +    { 0xB0088, 0x0, 0x11 },
> >> +};
> >> +
> >> +/* decoder properties */
> >> +static const u32 sm8550_vdec_psc_avc[] = {
> >> +    HFI_PROP_BITSTREAM_RESOLUTION,
> >> +    HFI_PROP_CROP_OFFSETS,
> >> +    HFI_PROP_CODED_FRAMES,
> >> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> >> +    HFI_PROP_PIC_ORDER_CNT_TYPE,
> >> +    HFI_PROP_PROFILE,
> >> +    HFI_PROP_LEVEL,
> >> +    HFI_PROP_SIGNAL_COLOR_INFO,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_psc_hevc[] = {
> >> +    HFI_PROP_BITSTREAM_RESOLUTION,
> >> +    HFI_PROP_CROP_OFFSETS,
> >> +    HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
> >> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> >> +    HFI_PROP_PROFILE,
> >> +    HFI_PROP_LEVEL,
> >> +    HFI_PROP_TIER,
> >> +    HFI_PROP_SIGNAL_COLOR_INFO,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_psc_vp9[] = {
> >> +    HFI_PROP_BITSTREAM_RESOLUTION,
> >> +    HFI_PROP_CROP_OFFSETS,
> >> +    HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
> >> +    HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
> >> +    HFI_PROP_PROFILE,
> >> +    HFI_PROP_LEVEL,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_input_properties_avc[] = {
> >> +    HFI_PROP_NO_OUTPUT,
> >> +    HFI_PROP_SUBFRAME_INPUT,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_input_properties_hevc[] = {
> >> +    HFI_PROP_NO_OUTPUT,
> >> +    HFI_PROP_SUBFRAME_INPUT,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_input_properties_vp9[] = {
> >> +    HFI_PROP_NO_OUTPUT,
> >> +    HFI_PROP_SUBFRAME_INPUT,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_output_properties_avc[] = {
> >> +    HFI_PROP_WORST_COMPRESSION_RATIO,
> >> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
> >> +    HFI_PROP_PICTURE_TYPE,
> >> +    HFI_PROP_DPB_LIST,
> >> +    HFI_PROP_CABAC_SESSION,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_output_properties_hevc[] = {
> >> +    HFI_PROP_WORST_COMPRESSION_RATIO,
> >> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
> >> +    HFI_PROP_PICTURE_TYPE,
> >> +    HFI_PROP_DPB_LIST,
> >> +};
> >> +
> >> +static const u32 sm8550_vdec_output_properties_vp9[] = {
> >> +    HFI_PROP_WORST_COMPRESSION_RATIO,
> >> +    HFI_PROP_WORST_COMPLEXITY_FACTOR,
> >> +    HFI_PROP_PICTURE_TYPE,
> >> +    HFI_PROP_DPB_LIST,
> >> +};
> >> +
> >> +static const struct msm_vidc_platform_data sm8550_data = {
> >> +    /* resources dependent on other module */
> >> +    .bw_tbl = sm8550_bw_table,
> >> +    .bw_tbl_size = ARRAY_SIZE(sm8550_bw_table),
> >> +    .clk_tbl = sm8550_clk_table,
> >> +    .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table),
> >> +    .clk_rst_tbl = sm8550_clk_reset_table,
> >> +    .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table),
> >> +    .subcache_tbl = NULL,
> >> +    .subcache_tbl_size = 0,
> >> +
> >> +    /* populate context bank */
> >> +    .context_bank_tbl = sm8550_context_bank_table,
> >> +    .context_bank_tbl_size = ARRAY_SIZE(sm8550_context_bank_table),
> >> +
> >> +    /* populate power domain and opp table */
> >> +    .pd_tbl = sm8550_pd_table,
> >> +    .pd_tbl_size = ARRAY_SIZE(sm8550_pd_table),
> >> +    .opp_tbl = sm8550_opp_table,
> >> +    .opp_tbl_size = ARRAY_SIZE(sm8550_opp_table),
> >> +
> >> +    /* platform specific resources */
> >> +    .freq_tbl = sm8550_freq_table,
> >> +    .freq_tbl_size = ARRAY_SIZE(sm8550_freq_table),
> >> +    .reg_prst_tbl = sm8550_reg_preset_table,
> >> +    .reg_prst_tbl_size = ARRAY_SIZE(sm8550_reg_preset_table),
> >> +    .fwname = "vpu30_4v",
> >> +    .pas_id = 9,
> >> +
> >> +    /* caps related resorces */
> >> +    .core_data = core_data_sm8550,
> >> +    .core_data_size = ARRAY_SIZE(core_data_sm8550),
> >> +    .inst_cap_data = instance_cap_data_sm8550,
> >> +    .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_sm8550),
> >> +    .inst_cap_dependency_data = instance_cap_dependency_data_sm8550,
> >> +    .inst_cap_dependency_data_size =
> >> ARRAY_SIZE(instance_cap_dependency_data_sm8550),
> >> +    .ubwc_config = ubwc_config_sm8550,
> >> +    .format_data = &format_data_sm8550,
> >> +
> >> +    /* decoder properties related*/
> >> +    .psc_avc_tbl = sm8550_vdec_psc_avc,
> >> +    .psc_avc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_avc),
> >> +    .psc_hevc_tbl = sm8550_vdec_psc_hevc,
> >> +    .psc_hevc_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_hevc),
> >> +    .psc_vp9_tbl = sm8550_vdec_psc_vp9,
> >> +    .psc_vp9_tbl_size = ARRAY_SIZE(sm8550_vdec_psc_vp9),
> >> +    .dec_input_prop_avc = sm8550_vdec_input_properties_avc,
> >> +    .dec_input_prop_hevc = sm8550_vdec_input_properties_hevc,
> >> +    .dec_input_prop_vp9 = sm8550_vdec_input_properties_vp9,
> >> +    .dec_input_prop_size_avc =
> >> ARRAY_SIZE(sm8550_vdec_input_properties_avc),
> >> +    .dec_input_prop_size_hevc =
> >> ARRAY_SIZE(sm8550_vdec_input_properties_hevc),
> >> +    .dec_input_prop_size_vp9 =
> >> ARRAY_SIZE(sm8550_vdec_input_properties_vp9),
> >> +    .dec_output_prop_avc = sm8550_vdec_output_properties_avc,
> >> +    .dec_output_prop_hevc = sm8550_vdec_output_properties_hevc,
> >> +    .dec_output_prop_vp9 = sm8550_vdec_output_properties_vp9,
> >> +    .dec_output_prop_size_avc =
> >> ARRAY_SIZE(sm8550_vdec_output_properties_avc),
> >> +    .dec_output_prop_size_hevc =
> >> ARRAY_SIZE(sm8550_vdec_output_properties_hevc),
> >> +    .dec_output_prop_size_vp9 =
> >> ARRAY_SIZE(sm8550_vdec_output_properties_vp9),
> >
> > Size should come next to the array reference.
> correct, will fix in next version
> >
> >> +};
> >> +
> >> +static int msm_vidc_init_data(struct msm_vidc_core *core)
> >> +{
> >> +    d_vpr_h("%s: initialize sm8550 data\n", __func__);
> >> +
> >> +    core->platform->data = sm8550_data;
> >> +
> >
> > Please use of_device_match_data() instead.
> >
> Thanks for the suggestion, will implement in next version.

BTW: could you please fix your mailer so that it doesn't insert extra
white space after your quoting level?

>
> Thanks,
> Dikshita
> >> +    return 0;
> >> +}
> >> +
> >> +int msm_vidc_init_platform_sm8550(struct msm_vidc_core *core)
> >> +{
> >> +    return msm_vidc_init_data(core);
> >> +}
> >



-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 03/33] iris: vidc: add v4l2 wrapper file
  2023-08-14 18:59     ` Dikshita Agarwal
@ 2023-08-14 21:19       ` Dmitry Baryshkov
  0 siblings, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-14 21:19 UTC (permalink / raw)
  To: Dikshita Agarwal
  Cc: Vikash Garodia, stanimir.k.varbanov, agross, andersson,
	konrad.dybcio, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm

On Mon, 14 Aug 2023 at 22:00, Dikshita Agarwal
<quic_dikshita@quicinc.com> wrote:
>
>
>
> On 7/28/2023 7:04 PM, Dmitry Baryshkov wrote:
> > On 28/07/2023 16:23, Vikash Garodia wrote:
> >> Here is the implementation of v4l2 wrapper functions for all
> >> v4l2 IOCTLs.
> >
> > Please do not describe the patch. "Here is..." , "This patch...", "This
> > commit..." is a bad style. Please describe _why_ you are doing this. In
> > other words, what is the purpose of adding such wrappers. Please rewrite
> > your commit messages describing the reasons, not the patch contents.
> >
> Sure, Will add descriptive commit text explaining the need of changes, in
> next version.

Please restructure your commits into functional chunks rather than
just committing file after file. This way you will have logical commit
messages for all your changes.

> >>
> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> >> ---
> >>   .../platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h    |  77 ++
> >>   .../platform/qcom/iris/vidc/src/msm_vidc_v4l2.c    | 953
> >> +++++++++++++++++++++
> >>   2 files changed, 1030 insertions(+)
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/vidc/inc/msm_vidc_v4l2.h
> >>   create mode 100644
> >> drivers/media/platform/qcom/iris/vidc/src/msm_vidc_v4l2.c




-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 10/33] iris: vidc: add helper functions
  2023-08-14 19:15     ` Dikshita Agarwal
@ 2023-08-16 11:46       ` Konrad Dybcio
  0 siblings, 0 replies; 108+ messages in thread
From: Konrad Dybcio @ 2023-08-16 11:46 UTC (permalink / raw)
  To: Dikshita Agarwal, Vikash Garodia, stanimir.k.varbanov, agross,
	andersson, mchehab, hans.verkuil, linux-kernel, linux-media,
	linux-arm-msm

On 14.08.2023 21:15, Dikshita Agarwal wrote:
> 
> 
> On 7/28/2023 11:11 PM, Konrad Dybcio wrote:
>> On 28.07.2023 15:23, Vikash Garodia wrote:
>>> This implements common helper functions for v4l2 to vidc and
>>> vice versa conversion for different enums.
>>> Add helpers for state checks, buffer management, locks etc.
>>>
>>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>>> ---
>> [...]
>>
>>> +
>>> +#define is_odd(val) ((val) % 2 == 1)
>>> +#define in_range(val, min, max) (((min) <= (val)) && ((val) <= (max)))
>>> +#define COUNT_BITS(a, out) {       \
>> hweight.* functions?
>>
>> [...]
>>
> sure, will replace with hweight.
>>> +
>>> +const char *cap_name(enum msm_vidc_inst_capability_type cap_id)
>>> +{
>>> +	const char *name = "UNKNOWN CAP";
>> Perhaps it'd be worth to include the unknown cap id here
>>
> could you please elaborate more on this.
>>> +
>>> +	if (cap_id >= ARRAY_SIZE(cap_name_arr))
>>> +		goto exit;
>>> +
>>> +	name = cap_name_arr[cap_id];
>>> +
>>> +exit:
>>> +	return name;
>>> +}
>> [...]
>>
>>> +
>>> +const char *buf_name(enum msm_vidc_buffer_type type)
>>> +{
>>> +	const char *name = "UNKNOWN BUF";
>> Similarly here
>>
> could you please elaborate more on this.
Something like "UNKNOWN BUF (0x15)" instead of just "UNKNOWN BUF"
would help us better understand whether the driver or the hardware
is missing something.


Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver
  2023-08-14 18:44     ` Dikshita Agarwal
@ 2023-08-16 12:00       ` Bryan O'Donoghue
  2023-08-16 13:14         ` Dmitry Baryshkov
  0 siblings, 1 reply; 108+ messages in thread
From: Bryan O'Donoghue @ 2023-08-16 12:00 UTC (permalink / raw)
  To: Dikshita Agarwal, Randy Dunlap, Vikash Garodia,
	stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm

On 14/08/2023 19:44, Dikshita Agarwal wrote:
> 
> 
> On 7/29/2023 4:18 AM, Randy Dunlap wrote:
>>
>>
>> On 7/28/23 06:23, Vikash Garodia wrote:
>>> Add an entry for Iris video encoder/decoder accelerator driver.
>>>
>>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>>> ---
>>>   MAINTAINERS | 10 ++++++++++
>>>   1 file changed, 10 insertions(+)
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 3be1bdf..ea633b2 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -17671,6 +17671,16 @@ T:	git git://linuxtv.org/media_tree.git
>>>   F:	Documentation/devicetree/bindings/media/*venus*
>>>   F:	drivers/media/platform/qcom/venus/
>>>   
>>> +QUALCOMM IRIS VIDEO ACCELERATOR DRIVER
>>
>> This entry should immediately follow:
>> QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER
>>
>> to keep the file in alphabetical order.
>>
> Sure, will fix this in next version.

I think TBH before we see a next version, there needs to be a conclusive 
argument on why a new driver - instead of an update to the existing 
venus - is the way to go.

We have an ongoing corpus of working code that people use. The attempt 
to at least _try_ to integrate 8550 and beyond to upstream venus should 
be made.

If it fails, then we can discuss a branched driver.

Its not up to me but, that's certainly my honest and unvarnished input.

Instead of investing time in V2 - please invest time in upstream venus 
or make the technical argument conclusively _prior_ to V2 as to why V2 
and beyond is the "only" way forward for 8550 and beyond.

---
bod


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver
  2023-08-16 12:00       ` Bryan O'Donoghue
@ 2023-08-16 13:14         ` Dmitry Baryshkov
  0 siblings, 0 replies; 108+ messages in thread
From: Dmitry Baryshkov @ 2023-08-16 13:14 UTC (permalink / raw)
  To: Bryan O'Donoghue
  Cc: Dikshita Agarwal, Randy Dunlap, Vikash Garodia,
	stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm

Hello,

On Wed, 16 Aug 2023 at 15:00, Bryan O'Donoghue
<bryan.odonoghue@linaro.org> wrote:
>
> On 14/08/2023 19:44, Dikshita Agarwal wrote:
> >
> >
> > On 7/29/2023 4:18 AM, Randy Dunlap wrote:
> >>
> >>
> >> On 7/28/23 06:23, Vikash Garodia wrote:
> >>> Add an entry for Iris video encoder/decoder accelerator driver.
> >>>
> >>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> >>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
> >>> ---
> >>>   MAINTAINERS | 10 ++++++++++
> >>>   1 file changed, 10 insertions(+)
> >>>
> >>> diff --git a/MAINTAINERS b/MAINTAINERS
> >>> index 3be1bdf..ea633b2 100644
> >>> --- a/MAINTAINERS
> >>> +++ b/MAINTAINERS
> >>> @@ -17671,6 +17671,16 @@ T: git git://linuxtv.org/media_tree.git
> >>>   F:        Documentation/devicetree/bindings/media/*venus*
> >>>   F:        drivers/media/platform/qcom/venus/
> >>>
> >>> +QUALCOMM IRIS VIDEO ACCELERATOR DRIVER
> >>
> >> This entry should immediately follow:
> >> QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER
> >>
> >> to keep the file in alphabetical order.
> >>
> > Sure, will fix this in next version.
>
> I think TBH before we see a next version, there needs to be a conclusive
> argument on why a new driver - instead of an update to the existing
> venus - is the way to go.
>
> We have an ongoing corpus of working code that people use. The attempt
> to at least _try_ to integrate 8550 and beyond to upstream venus should
> be made.
>
> If it fails, then we can discuss a branched driver.
>
> Its not up to me but, that's certainly my honest and unvarnished input.
>
> Instead of investing time in V2 - please invest time in upstream venus
> or make the technical argument conclusively _prior_ to V2 as to why V2
> and beyond is the "only" way forward for 8550 and beyond.

I'd second this request. At the very least (as I wrote in response to
another email), consider reworking venus into core and interface
specific parts and making iris3 use a common base layer.
We already have drivers which work across multiple platforms, taking
care of differences. Few to name: GPU, display, sound, DSP, camss.


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 00/33] Qualcomm video decoder/encoder driver
  2023-08-14 15:00     ` Dmitry Baryshkov
@ 2023-08-24 15:23       ` Vikash Garodia
  0 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-08-24 15:23 UTC (permalink / raw)
  To: Dmitry Baryshkov, Stanimir Varbanov
  Cc: agross, andersson, konrad.dybcio, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm, quic_dikshita

Hi Dmitry,

On 8/14/2023 8:30 PM, Dmitry Baryshkov wrote:
> Hi Stan,
> 
> On Mon, 14 Aug 2023 at 15:58, Stanimir Varbanov
> <stanimir.k.varbanov@gmail.com> wrote:
>>
>> Hi Dmitry,
>>
>> On 28.07.23 г. 17:01 ч., Dmitry Baryshkov wrote:
>>> On 28/07/2023 16:23, Vikash Garodia wrote:
>>>> This patch series introduces support for Qualcomm new video acceleration
>>>> hardware architecture, used for video stream decoding/encoding. This
>>>> driver
>>>> is based on new communication protocol between video hardware and
>>>> application
>>>> processor.
>>>>
>>>> This driver comes with below capabilities:
>>>> - V4L2 complaint video driver with M2M and STREAMING capability.
>>>> - Supports H264, H265, VP9 decoders.
>>>> - Supports H264, H265 encoders.
>>>
>>> Please describe, why is it impossible to support this hardware in the
>>> venus driver. We do not usually add new drivers for the new generations
>>> of the hardware, unless it is fully incompatible with the previous
>>> generations. Let me point you to camss or drm/msm drivers. They have
>>> successfully solved the issue of supporting multiple generations of the
>>> hardware in the same driver.
>>>
>>> Unless the "iris3" is completely different from all the previous
>>> generations, I strongly suggest spending time on restructuring existing
>>> venus driver and then adding support for the new hardware there instead
>>> of dumping out something completely new.
>>
>> AFAIK the major differences are HW IP and firmware interface (by
>> firmware interface I mean a protocol, API and API behavior). The
>> firmware and its interface has been re-written to align closely with the
>> current v4l2 specs for encoders/decoders state machines [1][2]. On the
>> other side current mainline Venus driver firmware is following interface
>> similar to OpenMAX.
>>
>> There are incompatibilities between both firmware interfaces which
>> cannot easily combined in a common driver. Even if there is a
>> possibility to do that it will lead us to a unreadable driver source
>> code and maintenance burden.
> 
> Thank you for your explanation!
> 
> If the hardware is more or less the same, then the existing venus
> driver should be refactored and split into hardware driver and the
> firmware interface. Then iris3 can come up as a second driver
> implementing support for new firmware interface but utilising common
> hardware-related code.

Its not just about supporting the new firmware interface because if that was the
case, it would have been a simple change. Its also about how the new firmware
interface affects the rest of the video sub-modules and state handling.
We incrementally evaluated whether putting the pieces one by one would make
sense but it doesn’t as every layer got affected and as a whole we decided to go
with this approach.
To elaborate more, let me try to put one of sequence which can provide info on
firmware interface and its handling across different video layers.

>> Vikash, could elaborate more on firmware interface differences.

Many new interfaces are added. Explained below one such video usecase of
handling dynamic resolution change (DRC) during drain. Illustrated a pseudo code
on how this will look if we fit this in venus driver.

- Client issues a STOP command. The command goes through state-wise command
handling, which also checks for cases like back to back drain. Vidc layer, which
handles common encoder and decoder functionality, routes it to decoder stop.
Decoder and driver layer then submits the command "HFI_CMD_DRAIN" to hardware
and moves the sub state to "MSM_VIDC_DRAIN".
- Now before drain is completed, there is a resolution change in one of the
frame queued before drain. Driver receives "HFI_CMD_SETTINGS_CHANGE" in hfi
response layer. The response goes through state check if received in intended
state and if good, changes the state to "MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE".
Any further input processing remain paused at this point. The decoder layer then
parses all the bitstream parameters which were subscribed by the driver.
V4L2_EVENT_SOURCE_CHANGE event is raised to client.
- Hardware respond with HFI_INFO_HFI_FLAG_PSC_LAST to indicate LAST frame with
old sequence. Driver substate is added with "MSM_VIDC_DRC_LAST_BUFFER |
MSM_VIDC_OUTPUT_PAUSE". At this point, driver is in state, STREAMING and
substate - MSM_VIDC_DRAIN | MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE |
MSM_VIDC_DRC_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE. This is when both hardware as
well as driver is paused while waiting for further instructions.
- Client issues START cmd. Vidc layer routes it to decoder layer which checks
for sub states and then allocates/queues internal buffers. At this point, DRC
sequence is completed and substates "MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER"
are cleared and both input and output planes are resumed with HFI
"HFI_CMD_RESUME". substate "MSM_VIDC_INPUT_PAUSE" and "MSM_VIDC_OUTPUT_PAUSE" is
cleared as well. So driver is in streaming state with sub state as "MSM_VIDC_DRAIN"
- Hardware issues a response to "HFI_CMD_DRAIN". As part of handling of this,
driver adds to sub state "MSM_VIDC_INPUT_PAUSE". This is done to avoid any
further input processing. Once all the frames are processed, hardware raises HFI
"HFI_INFO_HFI_FLAG_DRAIN_LAST". After doing state check, further sub states
"MSM_VIDC_DRAIN_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE" are added. So at this
point, the sub states are MSM_VIDC_DRAIN, MSM_VIDC_DRAIN_LAST_BUFFER,
MSM_VIDC_INPUT_PAUSE and MSM_VIDC_OUTPUT_PAUSE.
- Any pair calls like VIDIOC_STREAMON()/VIDIOC_STREAMOFF() on output or capture
queue, resets the substate to stream again.

If the same needs to be added in venus driver

- Client issues a STOP cmd to initiate drain. Decoder layer for stop handling
needs to be updated something like below //pseudo code  if (old interface)
   send dummy buffer
   change state to VENUS_DEC_STATE_DRAIN
   drain_active = true
 else
   statewise validation of STOP cmd
   state check for back to back drain
   issue HFI_CMD_DRAIN to hardware
   change sub state = MSM_VIDC_DRAIN

- DRC is issued by hardware
  if (old interface) //vdec and hfi response layer
   HFI_EVENT_SESSION_SEQUENCE_CHANGED with type
HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES
   changes state to VENUS_DEC_STATE_DRC
   next_buf_last = true
   flush (output)
   reconfig = true
   raise V4L2_EVENT_SOURCE_CHANGE event to client
  else
   HFI_CMD_SETTINGS_CHANGE // in hfi response layer
   state validation for intended state // in state handling layer
   sub state |= MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE
   raise V4L2_EVENT_SOURCE_CHANGE event to client

- LAST flag handling
  if (old interface)
    No LAST flag HFI from hardware
    in qbuf_capture
      if (next_buf_last) associated LAST flag
  else
    handle HFI_INFO_HFI_FLAG_PSC_LAST //in response layer
    sub state |= MSM_VIDC_DRC_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE

- Client issues START cmd
  if (old interface)
    does not handle VENUS_DEC_STATE_DRC state
  else
    sub state &= ~(MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER)
    allocates and queue internal buffer
    call HFI_CMD_RESUME for input and output
    sub state &= ~(MSM_VIDC_INPUT_PAUSE|MSM_VIDC_OUTPUT_PAUSE)

- Hardware response for HFI_CMD_DRAIN
  if (old interface)
    Nothing to do.
  else
    sub state |= MSM_VIDC_INPUT_PAUSE

- Handling for drain LAST flag
  if (old interface)
    receives dummy buffer with EOS
    converts to LAST and send to client
  else
    process HFI_INFO_HFI_FLAG_DRAIN_LAST
    sub state |= MSM_VIDC_DRAIN_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE

There are many such complex sequences which would add to complexity if we try to
fit them into existing driver.

> Do we have any details on firmware versions that implement older
> (OpenMAX-like) interface vs versions implementing new (v4l2-like)
> interface?
> 
>> [1]
>> https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html
>>
>> [2]
>> https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-encoder.html

Thanks,
Vikash

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 02/33] iris: vidc: add core functions
  2023-08-14 21:03       ` Dmitry Baryshkov
@ 2023-08-24 15:32         ` Vikash Garodia
  0 siblings, 0 replies; 108+ messages in thread
From: Vikash Garodia @ 2023-08-24 15:32 UTC (permalink / raw)
  To: Dmitry Baryshkov, Dikshita Agarwal
  Cc: stanimir.k.varbanov, agross, andersson, konrad.dybcio, mchehab,
	hans.verkuil, linux-kernel, linux-media, linux-arm-msm

Hi Dmitry,

On 8/15/2023 2:33 AM, Dmitry Baryshkov wrote:
> On Mon, 14 Aug 2023 at 21:58, Dikshita Agarwal
> <quic_dikshita@quicinc.com> wrote:
>>
>>
>>
>> On 7/28/2023 7:19 PM, Dmitry Baryshkov wrote:
>>> On 28/07/2023 16:23, Vikash Garodia wrote:
>>>> From: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>>>
>>>> This implements the platform driver methods, file
>>>> operations and v4l2 registration.
>>>>
>>>> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
>>>> Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
>>>> ---
>>>>   .../platform/qcom/iris/vidc/src/msm_vidc_probe.c   | 660
>>>> +++++++++++++++++++++
>>>>   1 file changed, 660 insertions(+)
>>>>   create mode 100644
>>>> drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>>>
>>>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>>> b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>>> new file mode 100644
>>>> index 0000000..43439cb
>>>> --- /dev/null
>>>> +++ b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_probe.c
>>>> @@ -0,0 +1,660 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
>>>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/iommu.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_platform.h>
>>>> +#include <linux/stringify.h>
>>>> +#include <linux/version.h>
>>>> +#include <linux/workqueue.h>
>>>> +
>>>> +#include "msm_vidc_core.h"
>>>> +#include "msm_vidc_debug.h"
>>>> +#include "msm_vidc_driver.h"
>>>> +#include "msm_vidc_internal.h"
>>>> +#include "msm_vidc_memory.h"
>>>> +#include "msm_vidc_platform.h"
>>>> +#include "msm_vidc_state.h"
>>>> +#include "venus_hfi.h"
>>>
>>> This files are not present yet, so this commit doesn't have a change of
>>> being compiled in any way.
>>>
>>>> +
>>>> +#define BASE_DEVICE_NUMBER 32
>>>> +
>>>> +struct msm_vidc_core *g_core;
>>>> +
>>>> +static inline bool is_video_device(struct device *dev)
>>>> +{
>>>> +    return !!(of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc"));
>>>
>>> Are you going to add future platforms to this list? Please don't duplicate
>>> of_match_data here.
>>> Sure, Will remove this API in next version.
>>>> +}
>>>> +
>>>> +static inline bool is_video_context_bank_device(struct device *dev)
>>>> +{
>>>> +    return !!(of_device_is_compatible(dev->of_node, "qcom,vidc,cb-ns"));
>>>> +}
>>>> +
>>>> +static int msm_vidc_init_resources(struct msm_vidc_core *core)
>>>> +{
>>>> +    struct msm_vidc_resource *res = NULL;
>>>> +    int rc = 0;
>>>> +
>>>> +    res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL);
>>>> +    if (!res) {
>>>> +        d_vpr_e("%s: failed to alloc memory for resource\n", __func__);
>>>
>>> Where is this macro defined? Please structure your comments in a logical
>>> way, so that one can read them from the beginning and understand what is
>>> going one.
>>>
>>> This is not to mention that adding such debugging wrappers doesn't have a
>>> lot of value.
>>>
>> I understand the concern here, will remove the custom debug wrappers in
>> next version.
>>>> +        return -ENOMEM;
>>>> +    }
>>>> +    core->resource = res;
>>>> +
>>>> +    rc = call_res_op(core, init, core);
>>>
>>> What is call_res_op?
>>>
>> This implements the resource ops, but as we don't need the abstraction for
>> resource ops, this will be removed in next version.
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
>>>> +        return rc;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static const struct of_device_id msm_vidc_dt_match[] = {
>>>> +    {.compatible = "qcom,sm8550-vidc"},
>>>> +    {.compatible = "qcom,vidc,cb-ns"},
>>>> +    MSM_VIDC_EMPTY_BRACE
>>>
>>> NO!!! Please use {} directly.
>>>
>> I Understand, will replace with {}.
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
>>>> +
>>>> +static void msm_vidc_release_video_device(struct video_device *vdev)
>>>> +{
>>>> +    d_vpr_e("%s: video device released\n", __func__);
>>>> +}
>>>> +
>>>> +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core,
>>>> +                         enum msm_vidc_domain_type type)
>>>> +{
>>>> +    int index;
>>>> +
>>>> +    if (type == MSM_VIDC_DECODER)
>>>> +        index = 0;
>>>> +    else if (type == MSM_VIDC_ENCODER)
>>>> +        index = 1;
>>>> +    else
>>>> +        return;
>>>
>>> You can index by the type instead of converting to index.
>>>
>> MSM_VIDC_DECODER/MSM_VIDC_ENCODER are bit masks hence can not be used as
>> array index and these bit mask values are being used in driver at multiple
>> places.
> 
> A subdevice can not be a decoder and an encoder at the same time, can
> it? So, please replace masks with indices.
> 
>>>> +
>>>> +    v4l2_m2m_release(core->vdev[index].m2m_dev);
>>>> +
>>>> +    video_set_drvdata(&core->vdev[index].vdev, NULL);
>>>> +    video_unregister_device(&core->vdev[index].vdev);
>>>> +}
>>>> +
>>>> +static int msm_vidc_register_video_device(struct msm_vidc_core *core,
>>>> +                      enum msm_vidc_domain_type type, int nr)
>>>> +{
>>>> +    int rc = 0;
>>>> +    int index;
>>>> +
>>>> +    d_vpr_h("%s: domain %d\n", __func__, type);
>>>> +
>>>> +    if (type == MSM_VIDC_DECODER)
>>>> +        index = 0;
>>>> +    else if (type == MSM_VIDC_ENCODER)
>>>> +        index = 1;
>>>> +    else
>>>> +        return -EINVAL;
>>>> +
>>>> +    core->vdev[index].vdev.release =
>>>> +        msm_vidc_release_video_device;
>>>> +    core->vdev[index].vdev.fops = core->v4l2_file_ops;
>>>> +    if (type == MSM_VIDC_DECODER)
>>>> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec;
>>>> +    else
>>>> +        core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc;
>>>> +    core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
>>>> +    core->vdev[index].type = type;
>>>> +    core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
>>>> +    core->vdev[index].vdev.device_caps =
>>>> core->capabilities[DEVICE_CAPS].value;
>>>> +    rc = video_register_device(&core->vdev[index].vdev,
>>>> +                   VFL_TYPE_VIDEO, nr);
>>>> +    if (rc) {
>>>> +        d_vpr_e("Failed to register the video device\n");
>>>> +        return rc;
>>>> +    }
>>>> +    video_set_drvdata(&core->vdev[index].vdev, core);
>>>> +
>>>> +    core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops);
>>>> +    if (IS_ERR(core->vdev[index].m2m_dev)) {
>>>> +        d_vpr_e("Failed to initialize V4L2 M2M device\n");
>>>> +        rc = PTR_ERR(core->vdev[index].m2m_dev);
>>>> +        goto m2m_init_failed;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +
>>>> +m2m_init_failed:
>>>> +    video_unregister_device(&core->vdev[index].vdev);
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
>>>> +{
>>>> +    int rc = 0;
>>>> +
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: invalid params\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    mutex_destroy(&core->lock);
>>>> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
>>>> +
>>>> +    if (core->batch_workq)
>>>> +        destroy_workqueue(core->batch_workq);
>>>> +
>>>> +    if (core->pm_workq)
>>>> +        destroy_workqueue(core->pm_workq);
>>>> +
>>>> +    core->batch_workq = NULL;
>>>> +    core->pm_workq = NULL;
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_initialize_core(struct msm_vidc_core *core)
>>>> +{
>>>> +    int rc = 0;
>>>> +
>>>> +    msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
>>>> +
>>>> +    core->pm_workq = create_singlethread_workqueue("pm_workq");
>>>> +    if (!core->pm_workq) {
>>>> +        d_vpr_e("%s: create pm workq failed\n", __func__);
>>>> +        rc = -EINVAL;
>>>> +        goto exit;
>>>> +    }
>>>> +
>>>> +    core->batch_workq = create_singlethread_workqueue("batch_workq");
>>>> +    if (!core->batch_workq) {
>>>> +        d_vpr_e("%s: create batch workq failed\n", __func__);
>>>> +        rc = -EINVAL;
>>>> +        goto exit;
>>>> +    }
>>>> +
>>>> +    core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE;
>>>> +    core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size,
>>>> GFP_KERNEL);
>>>> +    if (!core->packet) {
>>>> +        d_vpr_e("%s: failed to alloc core packet\n", __func__);
>>>> +        rc = -ENOMEM;
>>>> +        goto exit;
>>>> +    }
>>>> +
>>>> +    core->response_packet = devm_kzalloc(&core->pdev->dev,
>>>> core->packet_size, GFP_KERNEL);
>>>> +    if (!core->packet) {
>>>> +        d_vpr_e("%s: failed to alloc core response packet\n", __func__);
>>>> +        rc = -ENOMEM;
>>>> +        goto exit;
>>>> +    }
>>>> +
>>>> +    mutex_init(&core->lock);
>>>> +    INIT_LIST_HEAD(&core->instances);
>>>> +    INIT_LIST_HEAD(&core->dangling_instances);
>>>> +
>>>> +    INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
>>>> +    INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
>>>> +
>>>> +    return 0;
>>>> +exit:
>>>> +    if (core->batch_workq)
>>>> +        destroy_workqueue(core->batch_workq);
>>>> +    if (core->pm_workq)
>>>> +        destroy_workqueue(core->pm_workq);
>>>> +    core->batch_workq = NULL;
>>>> +    core->pm_workq = NULL;
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static void msm_vidc_devm_deinit_core(void *res)
>>>> +{
>>>> +    struct msm_vidc_core *core = res;
>>>> +
>>>> +    msm_vidc_deinitialize_core(core);
>>>> +}
>>>> +
>>>> +static int msm_vidc_devm_init_core(struct device *dev, struct
>>>> msm_vidc_core *core)
>>>> +{
>>>> +    int rc = 0;
>>>> +
>>>> +    if (!dev || !core) {
>>>> +        d_vpr_e("%s: invalid params\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_initialize_core(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init failed with %d\n", __func__, rc);
>>>> +        return rc;
>>>> +    }
>>>> +
>>>> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void
>>>> *)core);
>>>> +    if (rc)
>>>> +        return -EINVAL;
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static void msm_vidc_devm_debugfs_put(void *res)
>>>> +{
>>>> +    struct dentry *parent = res;
>>>> +
>>>> +    debugfs_remove_recursive(parent);
>>>> +}
>>>> +
>>>> +static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev)
>>>
>>> Why is it called get?
>>>
>> this will be removed in next version as part of debug wrappers removal
>>>
>>>> +{
>>>> +    struct dentry *parent = NULL;
>>>> +    int rc = 0;
>>>> +
>>>> +    if (!dev) {
>>>> +        d_vpr_e("%s: invalid params\n", __func__);
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    parent = msm_vidc_debugfs_init_drv();
>>>> +    if (!parent)
>>>> +        return NULL;
>>>> +
>>>> +    rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void
>>>> *)parent);
>>>> +    if (rc)
>>>> +        return NULL;
>>>> +
>>>> +    return parent;
>>>> +}
>>>> +
>>>> +static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
>>>> +                       struct device *dev)
>>>> +{
>>>> +    struct context_bank_info *cb = NULL;
>>>> +    int rc = 0;
>>>> +
>>>> +    cb = msm_vidc_get_context_bank_for_device(core, dev);
>>>> +    if (!cb) {
>>>> +        d_vpr_e("%s: Failed to get context bank device for %s\n",
>>>> +            __func__, dev_name(dev));
>>>> +        return -EIO;
>>>> +    }
>>>> +
>>>> +    /* populate dev & domain field */
>>>> +    cb->dev = dev;
>>>> +    cb->domain = iommu_get_domain_for_dev(cb->dev);
>>>> +    if (!cb->domain) {
>>>> +        d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__,
>>>> dev_name(dev));
>>>> +        return -EIO;
>>>> +    }
>>>> +
>>>> +    if (cb->dma_mask) {
>>>> +        rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask);
>>>> +        if (rc) {
>>>> +            d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__);
>>>> +            return rc;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * configure device segment size and segment boundary to ensure
>>>> +     * iommu mapping returns one mapping (which is required for partial
>>>> +     * cache operations)
>>>> +     */
>>>> +    if (!dev->dma_parms)
>>>> +        dev->dma_parms =
>>>> +            devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
>>>> +    dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
>>>> +    dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
>>>> +
>>>> +    iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler,
>>>> (void *)core);
>>>> +
>>>> +    d_vpr_h("%s: name %s addr start %x size %x secure %d\n",
>>>> +        __func__, cb->name, cb->addr_range.start,
>>>> +        cb->addr_range.size, cb->secure);
>>>> +    d_vpr_h("%s: dma_coherant %d region %d dev_name %s domain %pK
>>>> dma_mask %llu\n",
>>>> +        __func__, cb->dma_coherant, cb->region, dev_name(cb->dev),
>>>> +        cb->domain, cb->dma_mask);
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_remove_video_device(struct platform_device *pdev)
>>>> +{
>>>> +    struct msm_vidc_core *core;
>>>> +
>>>> +    if (!pdev) {
>>>> +        d_vpr_e("%s: invalid input %pK", __func__, pdev);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    core = dev_get_drvdata(&pdev->dev);
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: invalid core\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    msm_vidc_core_deinit(core, true);
>>>> +    venus_hfi_queue_deinit(core);
>>>> +
>>>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>>>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>>>> +
>>>> +    v4l2_device_unregister(&core->v4l2_dev);
>>>> +
>>>> +    d_vpr_h("depopulating sub devices\n");
>>>> +    /*
>>>> +     * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx
>>>> +     * When msm_vidc_remove is called for each sub-device, destroy
>>>> +     * context-bank mappings.
>>>> +     */
>>>> +    of_platform_depopulate(&pdev->dev);
>>>> +
>>>> +    dev_set_drvdata(&pdev->dev, NULL);
>>>> +    g_core = NULL;
>>>> +    d_vpr_h("%s(): succssful\n", __func__);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int msm_vidc_remove_context_bank(struct platform_device *pdev)
>>>> +{
>>>> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int msm_vidc_remove(struct platform_device *pdev)
>>>> +{
>>>> +    /*
>>>> +     * Sub devices remove will be triggered by of_platform_depopulate()
>>>> +     * after core_deinit(). It return immediately after completing
>>>> +     * sub-device remove.
>>>> +     */
>>>> +    if (is_video_device(&pdev->dev))
>>>> +        return msm_vidc_remove_video_device(pdev);
>>>> +    else if (is_video_context_bank_device(&pdev->dev))
>>>> +        return msm_vidc_remove_context_bank(pdev);
>>>> +
>>>> +    /* How did we end up here? */
>>>> +    WARN_ON(1);
>>>> +    return -EINVAL;
>>>> +}
>>>> +
>>>> +static int msm_vidc_probe_video_device(struct platform_device *pdev)
>>>> +{
>>>> +    int rc = 0;
>>>> +    struct msm_vidc_core *core = NULL;
>>>> +    int nr = BASE_DEVICE_NUMBER;
>>>> +
>>>> +    d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev));
>>>> +
>>>> +    core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core),
>>>> GFP_KERNEL);
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: failed to alloc memory for core\n", __func__);
>>>> +        return -ENOMEM;
>>>> +    }
>>>> +    g_core = core;
>>>> +
>>>> +    core->pdev = pdev;
>>>> +    dev_set_drvdata(&pdev->dev, core);
>>>> +
>>>> +    core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev);
>>>> +    if (!core->debugfs_parent)
>>>> +        d_vpr_h("Failed to create debugfs for msm_vidc\n");
>>>> +
>>>> +    rc = msm_vidc_devm_init_core(&pdev->dev, core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init core failed with %d\n", __func__, rc);
>>>> +        goto init_core_failed;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_init_platform(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
>>>> +        rc = -EINVAL;
>>>> +        goto init_plat_failed;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_init_resources(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init resource failed with %d\n", __func__, rc);
>>>> +        goto init_res_failed;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_init_core_caps(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init core caps failed with %d\n", __func__, rc);
>>>> +        goto init_res_failed;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_init_instance_caps(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc);
>>>> +        goto init_inst_caps_fail;
>>>> +    }
>>>> +
>>>> +    core->debugfs_root = msm_vidc_debugfs_init_core(core);
>>>> +    if (!core->debugfs_root)
>>>> +        d_vpr_h("Failed to init debugfs core\n");
>>>> +
>>>> +    d_vpr_h("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.
>>>> +     */
>>>> +    rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
>>>> +                  &pdev->dev);
>>>> +    if (rc) {
>>>> +        d_vpr_e("Failed to trigger probe for sub-devices\n");
>>>> +        goto sub_dev_failed;
>>>> +    }
>>>> +
>>>> +    rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
>>>> +    if (rc) {
>>>> +        d_vpr_e("Failed to register v4l2 device\n");
>>>> +        goto v4l2_reg_failed;
>>>> +    }
>>>> +
>>>> +    /* setup the decoder device */
>>>> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
>>>> +    if (rc) {
>>>> +        d_vpr_e("Failed to register video decoder\n");
>>>> +        goto dec_reg_failed;
>>>> +    }
>>>> +
>>>> +    /* setup the encoder device */
>>>> +    rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
>>>> +    if (rc) {
>>>> +        d_vpr_e("Failed to register video encoder\n");
>>>> +        goto enc_reg_failed;
>>>> +    }
>>>> +
>>>> +    rc = venus_hfi_queue_init(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: interface queues init failed\n", __func__);
>>>> +        goto queues_init_failed;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_core_init(core);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: sys init failed\n", __func__);
>>>> +        goto core_init_failed;
>>>> +    }
>>>> +
>>>> +    d_vpr_h("%s(): succssful\n", __func__);
>>>> +
>>>> +    return rc;
>>>> +
>>>> +core_init_failed:
>>>> +    venus_hfi_queue_deinit(core);
>>>> +queues_init_failed:
>>>> +    of_platform_depopulate(&pdev->dev);
>>>> +sub_dev_failed:
>>>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER);
>>>> +enc_reg_failed:
>>>> +    msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER);
>>>> +dec_reg_failed:
>>>> +    v4l2_device_unregister(&core->v4l2_dev);
>>>> +v4l2_reg_failed:
>>>> +init_inst_caps_fail:
>>>> +init_res_failed:
>>>> +init_plat_failed:
>>>> +init_core_failed:
>>>> +    dev_set_drvdata(&pdev->dev, NULL);
>>>> +    g_core = NULL;
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_probe_context_bank(struct platform_device *pdev)
>>>> +{
>>>> +    struct msm_vidc_core *core = NULL;
>>>> +    int rc = 0;
>>>> +
>>>> +    if (!pdev) {
>>>> +        d_vpr_e("%s: Invalid platform device %pK", __func__, pdev);
>>>> +        return -EINVAL;
>>>> +    } else if (!pdev->dev.parent) {
>>>> +        d_vpr_e("%s: Failed to find a parent for %s\n",
>>>> +            __func__, dev_name(&pdev->dev));
>>>> +        return -ENODEV;
>>>> +    }
>>>> +
>>>> +    d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev));
>>>> +
>>>> +    core = dev_get_drvdata(pdev->dev.parent);
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: core not found in device %s",
>>>> +            __func__, dev_name(pdev->dev.parent));
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_setup_context_bank(core, &pdev->dev);
>>>> +    if (rc) {
>>>> +        d_vpr_e("%s: Failed to probe context bank %s\n",
>>>> +            __func__, dev_name(&pdev->dev));
>>>> +        return rc;
>>>> +    }
>>>> +
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_probe(struct platform_device *pdev)
>>>> +{
>>>> +    if (!pdev) {
>>>> +        d_vpr_e("%s: invalid params\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * 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 (is_video_device(&pdev->dev))
>>>> +        return msm_vidc_probe_video_device(pdev);
>>>> +    else if (is_video_context_bank_device(&pdev->dev))
>>>> +        return msm_vidc_probe_context_bank(pdev);
>>>> +
>>>> +    /* How did we end up here? */
>>>> +    WARN_ON(1);
>>>> +    return -EINVAL;
>>>
>>> No. Please don't hack around the driver infrastructure and register two
>>> separate drivers. They can even come in two separate commits, simplifying
>>> the review.
>>>
>> Sure, will remove the separate probe for context bank in next version.
>>>> +}
>>>> +
>>>> +static int msm_vidc_pm_suspend(struct device *dev)
>>>> +{
>>>> +    int rc = 0;
>>>> +    struct msm_vidc_core *core;
>>>> +    enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
>>>> +
>>>> +    /*
>>>> +     * Bail out if
>>>> +     * - driver possibly not probed yet
>>>> +     * - not the main device. We don't support power management on
>>>> +     *   subdevices (e.g. context banks)
>>>> +     */
>>>> +    if (!dev || !dev->driver || !is_video_device(dev))
>>>> +        return 0;
>>>> +
>>>> +    core = dev_get_drvdata(dev);
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: invalid core\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    core_lock(core, __func__);
>>>> +    allow = msm_vidc_allow_pm_suspend(core);
>>>> +
>>>> +    if (allow == MSM_VIDC_IGNORE) {
>>>> +        d_vpr_h("%s: pm already suspended\n", __func__);
>>>> +        msm_vidc_change_core_sub_state(core, 0,
>>>> CORE_SUBSTATE_PM_SUSPEND, __func__);
>>>> +        rc = 0;
>>>> +        goto unlock;
>>>> +    } else if (allow != MSM_VIDC_ALLOW) {
>>>> +        d_vpr_h("%s: pm suspend not allowed\n", __func__);
>>>> +        rc = 0;
>>>> +        goto unlock;
>>>> +    }
>>>> +
>>>> +    rc = msm_vidc_suspend(core);
>>>> +    if (rc == -EOPNOTSUPP)
>>>> +        rc = 0;
>>>> +    else if (rc)
>>>> +        d_vpr_e("Failed to suspend: %d\n", rc);
>>>> +    else
>>>> +        msm_vidc_change_core_sub_state(core, 0,
>>>> CORE_SUBSTATE_PM_SUSPEND, __func__);
>>>> +
>>>> +unlock:
>>>> +    core_unlock(core, __func__);
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +static int msm_vidc_pm_resume(struct device *dev)
>>>> +{
>>>> +    struct msm_vidc_core *core;
>>>> +
>>>> +    /*
>>>> +     * Bail out if
>>>> +     * - driver possibly not probed yet
>>>> +     * - not the main device. We don't support power management on
>>>> +     *   subdevices (e.g. context banks)
>>>> +     */
>>>> +    if (!dev || !dev->driver || !is_video_device(dev))
>>>> +        return 0;
>>>> +
>>>> +    core = dev_get_drvdata(dev);
>>>> +    if (!core) {
>>>> +        d_vpr_e("%s: invalid core\n", __func__);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    /* remove PM suspend from core sub_state */
>>>> +    core_lock(core, __func__);
>>>> +    msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0,
>>>> __func__);
>>>> +    core_unlock(core, __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)
>>>
>>> No runtime PM?
>> runtime PM is not added in this series, but we plan to add it at later
>> point of time.
>>>
>>>> +};
>>>> +
>>>> +struct platform_driver msm_vidc_driver = {
>>>> +    .probe = msm_vidc_probe,
>>>> +    .remove = msm_vidc_remove,
>>>> +    .driver = {
>>>> +        .name = "msm_vidc_v4l2",
>>>> +        .of_match_table = msm_vidc_dt_match,
>>>> +        .pm = &msm_vidc_pm_ops,
>>>> +    },
>>>> +};
>>>> +
>>>> +module_platform_driver(msm_vidc_driver);
>>>> +MODULE_LICENSE("GPL");
>>>
>>> Unfortunately, after taking a glance at first two patches, I have to stop.
>>> It is nearly impossible to review it.
>>>
>>> Please start from the beginning, split the driver according to the logical
>>> functions, not per-file. Ideally something should be compillable starting
>>> from one of the first patches, if not the very first one. This would
>>> guarantee that your patchset is structured logically.

I agree on this. We are working on restructuring the patches as functional split
rather than file by file. As we plan to do this in the next revision, it might
take some time for V2.

>>>
>>> Please add DT bindings. New driver series should start from the bindings
>>> anyway.
>>>
>>> Please drop your custom debugging wrappers. Use dev_info, dev_warn, dev_err
>>> and dev_dbg instead.
>>>
>>> Please drop the custom multi-device-single-driver scheme. If there are
>>> different kinds of devices, there should be different drivers.
>>>
>>> Please take a look around. If you are pushing your driver for kernel
>>> inclusion, it should not stand out by the style and by the typical code
>>> seuqences.
>>
>> Thanks a lot for all your comments, will take care of these in next version.

Thanks,
Vikash

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [PATCH 11/33] iris: vidc: add helpers for memory management
  2023-08-14 19:06       ` Dikshita Agarwal
@ 2023-08-25 18:38         ` Konrad Dybcio
  0 siblings, 0 replies; 108+ messages in thread
From: Konrad Dybcio @ 2023-08-25 18:38 UTC (permalink / raw)
  To: Dikshita Agarwal, Bjorn Andersson, Vikash Garodia
  Cc: stanimir.k.varbanov, agross, andersson, mchehab, hans.verkuil,
	linux-kernel, linux-media, linux-arm-msm

On 14.08.2023 21:06, Dikshita Agarwal wrote:
> 
> 
> On 7/28/2023 10:52 PM, Konrad Dybcio wrote:
>> On 28.07.2023 18:28, Bjorn Andersson wrote:
>>> On Fri, Jul 28, 2023 at 06:53:22PM +0530, Vikash Garodia wrote:
>>>> diff --git a/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c b/drivers/media/platform/qcom/iris/vidc/src/msm_vidc_memory.c
>>> [..]
>>>> +static const struct msm_vidc_memory_ops msm_mem_ops = {
>>>> +	.dma_buf_get                    = msm_vidc_dma_buf_get,
>>>> +	.dma_buf_put                    = msm_vidc_dma_buf_put,
>>>> +	.dma_buf_put_completely         = msm_vidc_dma_buf_put_completely,
>>>> +	.dma_buf_attach                 = msm_vidc_dma_buf_attach,
>>>> +	.dma_buf_detach                 = msm_vidc_dma_buf_detach,
>>>> +	.dma_buf_map_attachment         = msm_vidc_dma_buf_map_attachment,
>>>> +	.dma_buf_unmap_attachment       = msm_vidc_dma_buf_unmap_attachment,
>>>> +	.memory_alloc_map               = msm_vidc_memory_alloc_map,
>>>> +	.memory_unmap_free              = msm_vidc_memory_unmap_free,
>>>> +	.buffer_region                  = msm_vidc_buffer_region,
>>>
>>> Will there ever be more than one implementation of the
>>> msm_vidc_memory_ops?
>>>
>>> Unless there's a really strong reason, just call the functions directly
>>> without the function pointers and call_mem_op(), this will be slightly
>>> faster, but more importantly it allows for much faster navigation of the
>>> code base.
>> Same for HFI ops
> Hi Konrad,
> There are no HFI ops in this driver, are you referring to anything else
> here, could you please point me to it?
Sorry, I had that in my brain cache after reading through the downstream
driver..

Konrad

^ permalink raw reply	[flat|nested] 108+ messages in thread

end of thread, other threads:[~2023-08-25 18:39 UTC | newest]

Thread overview: 108+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-28 13:23 [PATCH 00/33] Qualcomm video decoder/encoder driver Vikash Garodia
2023-07-28 13:23 ` [PATCH 01/33] MAINTAINERS: Add Qualcomm Iris video accelerator driver Vikash Garodia
2023-07-28 22:48   ` Randy Dunlap
2023-08-14 18:44     ` Dikshita Agarwal
2023-08-16 12:00       ` Bryan O'Donoghue
2023-08-16 13:14         ` Dmitry Baryshkov
2023-07-28 13:23 ` [PATCH 02/33] iris: vidc: add core functions Vikash Garodia
2023-07-28 13:45   ` Konrad Dybcio
2023-08-14 18:49     ` Dikshita Agarwal
2023-07-28 13:47   ` Konrad Dybcio
2023-07-28 13:49   ` Dmitry Baryshkov
2023-08-14 18:58     ` Dikshita Agarwal
2023-08-14 21:03       ` Dmitry Baryshkov
2023-08-24 15:32         ` Vikash Garodia
2023-07-31 21:16   ` Krzysztof Kozlowski
2023-08-14 18:54     ` Dikshita Agarwal
2023-08-14 20:04       ` Krzysztof Kozlowski
2023-07-31 21:23   ` Krzysztof Kozlowski
2023-08-14 18:51     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 03/33] iris: vidc: add v4l2 wrapper file Vikash Garodia
2023-07-28 13:34   ` Dmitry Baryshkov
2023-08-14 18:59     ` Dikshita Agarwal
2023-08-14 21:19       ` Dmitry Baryshkov
2023-07-28 16:23   ` Bjorn Andersson
2023-07-28 17:50   ` Nicolas Dufresne
2023-08-14 19:14     ` Dikshita Agarwal
2023-07-31 21:23   ` Krzysztof Kozlowski
2023-08-14 19:00     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 04/33] iris: add vidc " Vikash Garodia
2023-07-28 13:23 ` [PATCH 05/33] iris: vidc: add vb2 ops Vikash Garodia
2023-07-28 18:03   ` Nicolas Dufresne
2023-08-14 19:03     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 06/33] iris: vidc: define video core and instance context Vikash Garodia
2023-07-28 15:47   ` Bryan O'Donoghue
2023-08-14 19:04     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 07/33] iris: iris: add video encoder files Vikash Garodia
2023-07-28 13:23 ` [PATCH 08/33] iris: vidc: add video decoder files Vikash Garodia
2023-07-28 17:21   ` Konrad Dybcio
2023-08-14 19:13     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 09/33] iris: vidc: add control files Vikash Garodia
2023-07-28 13:23 ` [PATCH 10/33] iris: vidc: add helper functions Vikash Garodia
2023-07-28 17:41   ` Konrad Dybcio
2023-08-14 19:15     ` Dikshita Agarwal
2023-08-16 11:46       ` Konrad Dybcio
2023-07-28 13:23 ` [PATCH 11/33] iris: vidc: add helpers for memory management Vikash Garodia
2023-07-28 16:28   ` Bjorn Andersson
2023-07-28 17:22     ` Konrad Dybcio
2023-08-14 19:06       ` Dikshita Agarwal
2023-08-25 18:38         ` Konrad Dybcio
2023-08-14 19:05     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 12/33] iris: vidc: add helper functions for resource management Vikash Garodia
2023-07-28 17:30   ` Konrad Dybcio
2023-08-14 19:07     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 13/33] iris: vidc: add helper functions for power management Vikash Garodia
2023-07-28 17:46   ` Konrad Dybcio
2023-08-14 19:10     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 14/33] iris: vidc: add helpers for state management Vikash Garodia
2023-07-28 17:52   ` Konrad Dybcio
2023-08-14 19:17     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 15/33] iris: add vidc buffer files Vikash Garodia
2023-07-28 13:23 ` [PATCH 16/33] iris: add helpers for media format Vikash Garodia
2023-07-28 17:55   ` Konrad Dybcio
2023-08-14 19:18     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 17/33] iris: vidc: define various structures and enum Vikash Garodia
2023-07-28 13:23 ` [PATCH 18/33] iris: vidc: hfi: add Host Firmware Interface (HFI) Vikash Garodia
2023-07-28 15:58   ` Bryan O'Donoghue
2023-08-14 19:11     ` Dikshita Agarwal
2023-07-31  9:02   ` Bryan O'Donoghue
2023-08-14 19:11     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 19/33] iris: vidc: hfi: add Host Firmware Interface (HFI) response handling Vikash Garodia
2023-07-28 13:23 ` [PATCH 20/33] iris: vidc: hfi: add helpers for handling shared queues Vikash Garodia
2023-07-28 17:58   ` Konrad Dybcio
2023-08-14 19:19     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 21/33] iris: vidc: hfi: Add packetization layer Vikash Garodia
2023-07-28 13:23 ` [PATCH 22/33] iris: vidc: hfi: defines HFI properties and enums Vikash Garodia
2023-07-28 13:23 ` [PATCH 23/33] iris: vidc: add PIL functionality for video firmware Vikash Garodia
2023-07-28 13:23 ` [PATCH 24/33] iris: vidc: add debug files Vikash Garodia
2023-07-31 21:31   ` Krzysztof Kozlowski
2023-08-14 19:12     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 25/33] iris: platform: add platform files Vikash Garodia
2023-07-28 13:23 ` [PATCH 26/33] iris: platform: sm8550: add capability file for sm8550 Vikash Garodia
2023-07-28 14:13   ` Dmitry Baryshkov
2023-08-14 19:35     ` Dikshita Agarwal
2023-08-14 21:17       ` Dmitry Baryshkov
2023-07-28 13:23 ` [PATCH 27/33] iris: variant: add helper functions for register handling Vikash Garodia
2023-07-28 13:23 ` [PATCH 28/33] iris: variant: iris3: add iris3 specific ops Vikash Garodia
2023-07-28 13:23 ` [PATCH 29/33] iris: variant: iris3: add helpers for buffer size calculations Vikash Garodia
2023-07-28 14:19   ` Dmitry Baryshkov
2023-08-14 20:00     ` Dikshita Agarwal
2023-08-14 20:59       ` Dmitry Baryshkov
2023-07-28 13:23 ` [PATCH 30/33] iris: variant: iris3: add helper for bus and clock calculation Vikash Garodia
2023-07-28 13:23 ` [PATCH 31/33] iris: variant: iris: implement the logic to compute bus bandwidth Vikash Garodia
2023-07-28 18:09   ` Konrad Dybcio
2023-08-14 19:21     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 32/33] iris: variant: iris3: implement logic to compute clock frequency Vikash Garodia
2023-07-28 18:13   ` Konrad Dybcio
2023-08-14 19:25     ` Dikshita Agarwal
2023-07-28 13:23 ` [PATCH 33/33] iris: enable building of iris video driver Vikash Garodia
2023-07-28 14:40   ` Dmitry Baryshkov
2023-07-28 15:25   ` Bryan O'Donoghue
2023-07-28 15:51     ` Dmitry Baryshkov
2023-07-28 13:32 ` [PATCH 00/33] Qualcomm video decoder/encoder driver Dmitry Baryshkov
2023-07-28 17:38   ` Nicolas Dufresne
2023-07-28 14:01 ` Dmitry Baryshkov
2023-08-14 12:58   ` Stanimir Varbanov
2023-08-14 15:00     ` Dmitry Baryshkov
2023-08-24 15:23       ` Vikash Garodia
2023-07-28 14:34 ` Bryan O'Donoghue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).