diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/media/platform/qcom/vcodec/iris/Makefile
index a2d5d74..90241b5 100644
--- a/drivers/media/platform/qcom/vcodec/iris/Makefile
+++ b/drivers/media/platform/qcom/vcodec/iris/Makefile
@@ -7,6 +7,8 @@ iris-objs += iris_probe.o \
              iris_helpers.o \
              iris_hfi.o \
              iris_hfi_packet.o \
-             resources.o
+             resources.o \
+             vpu_common.o \
+             vpu_iris3.o
 
 obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index de0cfef..64678fd 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -12,6 +12,7 @@
 #include "../hfi_queue.h"
 #include "iris_state.h"
 #include "resources.h"
+#include "vpu_common.h"
 
 /**
  * struct iris_core - holds core parameters valid for all instances
@@ -44,6 +45,7 @@
  * @sys_init_id: id of sys init packet
  * @header_id: id of packet header
  * @packet_id: id of packet
+ * @vpu_ops: a pointer to vpu ops
  */
 
 struct iris_core {
@@ -75,6 +77,7 @@ struct iris_core {
 	u32					sys_init_id;
 	u32					header_id;
 	u32					packet_id;
+	const struct vpu_ops			*vpu_ops;
 };
 
 int iris_core_init(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
index fe16448..7b3cbbc 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
@@ -8,6 +8,7 @@
 #include "iris_helpers.h"
 #include "iris_hfi.h"
 #include "iris_hfi_packet.h"
+#include "vpu_common.h"
 
 static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
 {
@@ -33,6 +34,8 @@ static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
 	packet_size = header->size;
 
 	if (!write_queue(q_info, pkt, packet_size, &rx_req)) {
+		call_vpu_op(core, raise_interrupt, core);
+	} else {
 		dev_err(core->dev, "queue full\n");
 		return -ENODATA;
 	}
@@ -108,6 +111,10 @@ int iris_hfi_core_init(struct iris_core *core)
 	if (ret)
 		goto error;
 
+	ret = call_vpu_op(core, boot_firmware, core);
+	if (ret)
+		goto error;
+
 	ret = sys_init(core);
 	if (ret)
 		goto error;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
index 570c64e..773481f 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
@@ -92,6 +92,13 @@ static int iris_probe(struct platform_device *pdev)
 	if (core->irq < 0)
 		return core->irq;
 
+	ret = init_vpu(core);
+	if (ret) {
+		dev_err_probe(core->dev, ret,
+			      "%s: init vpu failed with %d\n", __func__, ret);
+		return ret;
+	}
+
 	ret = init_resources(core);
 	if (ret) {
 		dev_err_probe(core->dev, ret,
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_common.c b/drivers/media/platform/qcom/vcodec/iris/vpu_common.c
new file mode 100644
index 0000000..3282510
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_common.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "vpu_iris3.h"
+#include "iris_core.h"
+#include "iris_helpers.h"
+#include "vpu_common.h"
+
+int write_register(struct iris_core *core, u32 reg, u32 value)
+{
+	void __iomem *base_addr;
+	int ret;
+
+	ret = check_core_lock(core);
+	if (ret)
+		return ret;
+
+	base_addr = core->reg_base;
+	base_addr += reg;
+	writel_relaxed(value, base_addr);
+
+	/* Make sure value is written into the register */
+	wmb();
+
+	return ret;
+}
+
+int read_register(struct iris_core *core, u32 reg, u32 *value)
+{
+	void __iomem *base_addr;
+
+	base_addr = core->reg_base;
+
+	*value = readl_relaxed(base_addr + reg);
+
+	/* Make sure value is read correctly from the register */
+	rmb();
+
+	return 0;
+}
+
+static const struct compat_handle compat_handle[] = {
+	{
+		.compat                  = "qcom,sm8550-iris",
+		.init                    = init_iris3,
+	},
+};
+
+int init_vpu(struct iris_core *core)
+{
+	struct device *dev = NULL;
+	int i, ret = 0;
+
+	dev = core->dev;
+
+	for (i = 0; i < ARRAY_SIZE(compat_handle); i++) {
+		if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) {
+			ret = compat_handle[i].init(core);
+			if (ret)
+				return ret;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(compat_handle))
+		return -EINVAL;
+
+	return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_common.h b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
new file mode 100644
index 0000000..790496a
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VPU_COMMON_H_
+#define _VPU_COMMON_H_
+
+#include <linux/types.h>
+
+struct iris_core;
+
+#define call_vpu_op(d, op, ...)			\
+	(((d) && (d)->vpu_ops && (d)->vpu_ops->op) ? \
+	((d)->vpu_ops->op(__VA_ARGS__)) : 0)
+
+struct compat_handle {
+	const char *compat;
+	int (*init)(struct iris_core *core);
+};
+
+struct vpu_ops {
+	int (*boot_firmware)(struct iris_core *core);
+	int (*raise_interrupt)(struct iris_core *core);
+};
+
+int init_vpu(struct iris_core *core);
+
+int write_register(struct iris_core *core, u32 reg, u32 value);
+int read_register(struct iris_core *core, u32 reg, u32 *value);
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
new file mode 100644
index 0000000..95bf223
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/delay.h>
+
+#include "vpu_iris3.h"
+
+#define VIDEO_ARCH_LX 1
+
+#define CPU_BASE_OFFS_IRIS3     0x000A0000
+
+#define CPU_CS_BASE_OFFS_IRIS3      (CPU_BASE_OFFS_IRIS3)
+#define CPU_IC_BASE_OFFS_IRIS3      (CPU_BASE_OFFS_IRIS3)
+
+#define CPU_CS_VCICMDARG0_IRIS3     (CPU_CS_BASE_OFFS_IRIS3 + 0x24)
+#define CPU_CS_VCICMDARG1_IRIS3     (CPU_CS_BASE_OFFS_IRIS3 + 0x28)
+
+/* HFI_CTRL_INIT */
+#define CPU_CS_SCIACMD_IRIS3        (CPU_CS_BASE_OFFS_IRIS3 + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define CPU_CS_SCIACMDARG0_IRIS3    (CPU_CS_BASE_OFFS_IRIS3 + 0x4C)
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3     0x40000000
+
+#define CPU_CS_H2XSOFTINTEN_IRIS3   (CPU_CS_BASE_OFFS_IRIS3 + 0x148)
+
+#define CPU_CS_X2RPMH_IRIS3         (CPU_CS_BASE_OFFS_IRIS3 + 0x168)
+
+/* 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)
+
+/* 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)
+
+/* SFR_ADDR */
+#define CPU_CS_SCIBCMD_IRIS3        (CPU_CS_BASE_OFFS_IRIS3 + 0x5C)
+
+#define UC_REGION_ADDR_IRIS3        CPU_CS_SCIBARG1_IRIS3
+#define UC_REGION_SIZE_IRIS3	    CPU_CS_SCIBARG2_IRIS3
+
+#define QTBL_INFO_IRIS3             CPU_CS_SCIACMDARG1_IRIS3
+#define QTBL_ADDR_IRIS3             CPU_CS_SCIACMDARG2_IRIS3
+
+#define SFR_ADDR_IRIS3              CPU_CS_SCIBCMD_IRIS3
+
+#define CTRL_INIT_IRIS3             CPU_CS_SCIACMD_IRIS3
+
+#define CTRL_STATUS_IRIS3           CPU_CS_SCIACMDARG0_IRIS3
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3	0xfe
+#define CTRL_ERROR_STATUS__M_IRIS3 \
+		CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3
+
+#define CPU_IC_SOFTINT_IRIS3        (CPU_IC_BASE_OFFS_IRIS3 + 0x150)
+#define CPU_IC_SOFTINT_H2A_SHFT_IRIS3	0x0
+
+static int setup_ucregion_memory_map_iris3(struct iris_core *core)
+{
+	int ret;
+	u32 value;
+
+	value = (u32)core->iface_q_table.device_addr;
+	ret = write_register(core, UC_REGION_ADDR_IRIS3, value);
+	if (ret)
+		return ret;
+
+	value = SHARED_QSIZE;
+	ret = write_register(core, UC_REGION_SIZE_IRIS3, value);
+	if (ret)
+		return ret;
+
+	value = (u32)core->iface_q_table.device_addr;
+	ret = write_register(core, QTBL_ADDR_IRIS3, value);
+	if (ret)
+		return ret;
+
+	ret = write_register(core, QTBL_INFO_IRIS3, 0x01);
+	if (ret)
+		return ret;
+
+	value = (u32)((u64)core->iface_q_table.kernel_vaddr);
+	ret = write_register(core, CPU_CS_VCICMDARG0_IRIS3, value);
+	if (ret)
+		return ret;
+
+	value = (u32)((u64)core->iface_q_table.kernel_vaddr >> 32);
+	ret = write_register(core, CPU_CS_VCICMDARG1_IRIS3, value);
+	if (ret)
+		return ret;
+
+	if (core->sfr.device_addr) {
+		value = (u32)core->sfr.device_addr + VIDEO_ARCH_LX;
+		ret = write_register(core, SFR_ADDR_IRIS3, value);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int boot_firmware_iris3(struct iris_core *core)
+{
+	u32 ctrl_init = 0, ctrl_status = 0, count = 0, max_tries = 1000;
+	int ret;
+
+	ret = setup_ucregion_memory_map_iris3(core);
+	if (ret)
+		return ret;
+
+	ctrl_init = BIT(0);
+
+	ret = write_register(core, CTRL_INIT_IRIS3, ctrl_init);
+	if (ret)
+		return ret;
+
+	while (!ctrl_status && count < max_tries) {
+		ret = read_register(core, CTRL_STATUS_IRIS3, &ctrl_status);
+		if (ret)
+			return ret;
+
+		if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS3) == 0x4) {
+			dev_err(core->dev, "invalid setting for UC_REGION\n");
+			break;
+		}
+
+		usleep_range(50, 100);
+		count++;
+	}
+
+	if (count >= max_tries) {
+		dev_err(core->dev, "Error booting up vidc firmware\n");
+		return -ETIME;
+	}
+
+	ret = write_register(core, CPU_CS_H2XSOFTINTEN_IRIS3, 0x1);
+	if (ret)
+		return ret;
+
+	ret = write_register(core, CPU_CS_X2RPMH_IRIS3, 0x0);
+
+	return ret;
+}
+
+static int raise_interrupt_iris3(struct iris_core *core)
+{
+	return write_register(core, CPU_IC_SOFTINT_IRIS3, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS3);
+}
+
+static const struct vpu_ops iris3_ops = {
+	.boot_firmware = boot_firmware_iris3,
+	.raise_interrupt = raise_interrupt_iris3,
+};
+
+int init_iris3(struct iris_core *core)
+{
+	core->vpu_ops = &iris3_ops;
+
+	return 0;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h
new file mode 100644
index 0000000..1424a5f
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VPU_IRIS3_H_
+#define _VPU_IRIS3_H_
+
+#include "iris_core.h"
+
+int init_iris3(struct iris_core *core);
+
+#endif
