diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/media/platform/qcom/vcodec/iris/Makefile
index 3c076d0..85fdf63 100644
--- a/drivers/media/platform/qcom/vcodec/iris/Makefile
+++ b/drivers/media/platform/qcom/vcodec/iris/Makefile
@@ -8,6 +8,7 @@ iris-objs += iris_probe.o \
              iris_state.o \
              iris_helpers.o \
              iris_hfi.o \
+             iris_hfi_response.o \
              iris_hfi_packet.o \
              resources.o \
              vpu_common.o \
diff --git a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
index 423ba1a..9dd5f11 100644
--- a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
+++ b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
@@ -6,6 +6,8 @@
 #ifndef _HFI_DEFINES_H_
 #define _HFI_DEFINES_H_
 
+#include <linux/types.h>
+
 #define HFI_VIDEO_ARCH_LX			0x1
 
 #define HFI_CMD_INIT				0x01000001
@@ -50,4 +52,12 @@
 
 #define HFI_PROP_DEC_START_FROM_RAP_FRAME	0x03000169
 
+#define HFI_SYS_ERROR_WD_TIMEOUT		0x05000001
+
+struct hfi_debug_header {
+	u32   size;
+	u32   debug_level;
+	u32   reserved[2];
+};
+
 #endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index b47520a..c125bce 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -45,6 +45,7 @@
  * @use_tz: a flag that suggests presence of trustzone
  * @packet: pointer to packet from driver to fw
  * @packet_size: size of packet
+ * @response_packet: a pointer to response packet from fw to driver
  * @sys_init_id: id of sys init packet
  * @header_id: id of packet header
  * @packet_id: id of packet
@@ -52,6 +53,7 @@
  * @platform_data: a structure for platform data
  * @cap: an array for supported core capabilities
  * @instances: a list_head of all instances
+ * @intr_status: interrupt status
  */
 
 struct iris_core {
@@ -82,6 +84,7 @@ struct iris_core {
 	unsigned int				use_tz;
 	u8					*packet;
 	u32					packet_size;
+	u8					*response_packet;
 	u32					sys_init_id;
 	u32					header_id;
 	u32					packet_id;
@@ -89,6 +92,7 @@ struct iris_core {
 	struct platform_data			*platform_data;
 	struct plat_core_cap			cap[CORE_CAP_MAX + 1];
 	struct list_head			instances;
+	u32					intr_status;
 };
 
 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 d144ae5..4b8d8c7 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
@@ -5,10 +5,11 @@
 
 #include "../firmware.h"
 #include "../hfi_queue.h"
+#include "hfi_defines.h"
 #include "iris_helpers.h"
 #include "iris_hfi.h"
 #include "iris_hfi_packet.h"
-#include "hfi_defines.h"
+#include "iris_hfi_response.h"
 #include "vpu_common.h"
 
 static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
@@ -253,3 +254,29 @@ int iris_hfi_session_close(struct iris_inst *inst)
 
 	return ret;
 }
+
+irqreturn_t iris_hfi_isr(int irq, void *data)
+{
+	disable_irq_nosync(irq);
+
+	return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t iris_hfi_isr_handler(int irq, void *data)
+{
+	struct iris_core *core = data;
+
+	if (!core)
+		return IRQ_NONE;
+
+	mutex_lock(&core->lock);
+	call_vpu_op(core, clear_interrupt, core);
+	mutex_unlock(&core->lock);
+
+	__response_handler(core);
+
+	if (!call_vpu_op(core, watchdog, core, core->intr_status))
+		enable_irq(irq);
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
index 8a057cc..8a62986 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
@@ -14,4 +14,7 @@ int iris_hfi_core_deinit(struct iris_core *core);
 int iris_hfi_session_open(struct iris_inst *inst);
 int iris_hfi_session_close(struct iris_inst *inst);
 
+irqreturn_t iris_hfi_isr(int irq, void *data);
+irqreturn_t iris_hfi_isr_handler(int irq, void *data);
+
 #endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
new file mode 100644
index 0000000..829f3f6
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_defines.h"
+#include "iris_hfi_packet.h"
+#include "iris_hfi_response.h"
+
+static void print_sfr_message(struct iris_core *core)
+{
+	struct sfr_buffer *vsfr = NULL;
+	u32 vsfr_size = 0;
+	void *p = NULL;
+
+	vsfr = (struct sfr_buffer *)core->sfr.kernel_vaddr;
+	if (vsfr) {
+		if (vsfr->bufsize != core->sfr.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';
+	}
+}
+
+static int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+			   u32 core_resp_pkt_size)
+{
+	u32 response_pkt_size = 0;
+	u8 *response_limit;
+
+	if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size)
+		return -EINVAL;
+
+	response_limit = core_resp_pkt + core_resp_pkt_size;
+
+	if (response_pkt < core_resp_pkt || response_pkt > response_limit)
+		return -EINVAL;
+
+	response_pkt_size = *(u32 *)response_pkt;
+	if (!response_pkt_size)
+		return -EINVAL;
+
+	if (response_pkt_size < sizeof(struct hfi_packet))
+		return -EINVAL;
+
+	if (response_pkt + response_pkt_size > response_limit)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int validate_hdr_packet(struct iris_core *core,
+			       struct hfi_header *hdr)
+{
+	struct hfi_packet *packet;
+	int i, ret = 0;
+	u8 *pkt;
+
+	if (hdr->size < sizeof(*hdr) + sizeof(*packet))
+		return -EINVAL;
+
+	pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
+
+	for (i = 0; i < hdr->num_packets; i++) {
+		packet = (struct hfi_packet *)pkt;
+		ret = validate_packet(pkt, core->response_packet, core->packet_size);
+		if (ret)
+			return ret;
+
+		pkt += packet->size;
+	}
+
+	return ret;
+}
+
+static int handle_system_error(struct iris_core *core,
+			       struct hfi_packet *pkt)
+{
+	print_sfr_message(core);
+
+	iris_core_deinit(core);
+
+	return 0;
+}
+
+static int handle_response(struct iris_core *core, void *response)
+{
+	struct hfi_header *hdr;
+	int ret;
+
+	hdr = (struct hfi_header *)response;
+	ret = validate_hdr_packet(core, hdr);
+	if (ret)
+		return handle_system_error(core, NULL);
+
+	return ret;
+}
+
+static int iris_hfi_queue_read(struct iris_core *core, void *pkt,
+			       struct iface_q_info *q_info)
+{
+	u32 tx_req;
+
+	if (!core_in_valid_state(core))
+		return -EINVAL;
+
+	if (!q_info || !q_info->q_array.kernel_vaddr || !pkt) {
+		dev_err(core->dev, "cannot read from shared Q's\n");
+		return -ENODATA;
+	}
+
+	if (read_queue(q_info, pkt, &tx_req))
+		return -ENODATA;
+
+	return 0;
+}
+
+int __response_handler(struct iris_core *core)
+{
+	int ret = 0;
+
+	if (call_vpu_op(core, watchdog, core, core->intr_status)) {
+		struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT};
+
+		mutex_lock(&core->lock);
+		iris_change_core_state(core, IRIS_CORE_ERROR);
+		dev_err(core->dev, "%s: CPU WD error received\n", __func__);
+		mutex_unlock(&core->lock);
+
+		return handle_system_error(core, &pkt);
+	}
+
+	memset(core->response_packet, 0, core->packet_size);
+	while (!iris_hfi_queue_read(core, core->response_packet, &core->message_queue)) {
+		ret = handle_response(core, core->response_packet);
+		if (ret)
+			continue;
+		if (core->state != IRIS_CORE_INIT)
+			break;
+		memset(core->response_packet, 0, core->packet_size);
+	}
+
+	iris_flush_debug_queue(core, core->response_packet, core->packet_size);
+
+	return ret;
+}
+
+void iris_flush_debug_queue(struct iris_core *core,
+			    u8 *packet, u32 packet_size)
+{
+	struct hfi_debug_header *pkt;
+	bool local_packet = false;
+	u8 *log;
+
+	if (!packet || !packet_size) {
+		packet = kzalloc(IFACEQ_CORE_PKT_SIZE, GFP_KERNEL);
+		if (!packet)
+			return;
+
+		packet_size = IFACEQ_CORE_PKT_SIZE;
+
+		local_packet = true;
+	}
+
+	while (!iris_hfi_queue_read(core, packet, &core->debug_queue)) {
+		pkt = (struct hfi_debug_header *)packet;
+
+		if (pkt->size < sizeof(*pkt))
+			continue;
+
+		if (pkt->size >= packet_size)
+			continue;
+
+		packet[pkt->size] = '\0';
+		log = (u8 *)packet + sizeof(*pkt) + 1;
+		dev_dbg(core->dev, "%s", log);
+	}
+
+	if (local_packet)
+		kfree(packet);
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.h
new file mode 100644
index 0000000..c1d2d27
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _IRIS_HFI_RESPONSE_H_
+#define _IRIS_HFI_RESPONSE_H_
+
+#include "iris_core.h"
+
+struct sfr_buffer {
+	u32 bufsize;
+	u8 rg_data[];
+};
+
+int __response_handler(struct iris_core *core);
+void iris_flush_debug_queue(struct iris_core *core,
+			    u8 *packet, u32 packet_size);
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
index 4f20da8..8c591da 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
@@ -10,9 +10,25 @@
 #include "../hfi_queue.h"
 #include "iris_core.h"
 #include "iris_helpers.h"
+#include "iris_hfi.h"
 #include "resources.h"
 #include "iris_vidc.h"
 
+static int init_iris_isr(struct iris_core *core)
+{
+	int ret;
+
+	ret = devm_request_threaded_irq(core->dev, core->irq, iris_hfi_isr,
+					iris_hfi_isr_handler, IRQF_TRIGGER_HIGH, "iris", core);
+	if (ret) {
+		dev_err(core->dev, "%s: Failed to allocate iris IRQ\n", __func__);
+		return ret;
+	}
+	disable_irq_nosync(core->irq);
+
+	return ret;
+}
+
 static int iris_register_video_device(struct iris_core *core)
 {
 	struct video_device *vdev;
@@ -86,6 +102,10 @@ static int iris_probe(struct platform_device *pdev)
 	if (!core->packet)
 		return -ENOMEM;
 
+	core->response_packet = devm_kzalloc(core->dev, core->packet_size, GFP_KERNEL);
+	if (!core->response_packet)
+		return -ENOMEM;
+
 	INIT_LIST_HEAD(&core->instances);
 
 	core->reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -96,6 +116,13 @@ static int iris_probe(struct platform_device *pdev)
 	if (core->irq < 0)
 		return core->irq;
 
+	ret = init_iris_isr(core);
+	if (ret) {
+		dev_err_probe(core->dev, ret,
+			      "%s: Failed to init isr with %d\n", __func__, ret);
+		return ret;
+	}
+
 	ret = init_platform(core);
 	if (ret) {
 		dev_err_probe(core->dev, ret,
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_common.h b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
index 790496a..6512039 100644
--- a/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
@@ -22,6 +22,8 @@ struct compat_handle {
 struct vpu_ops {
 	int (*boot_firmware)(struct iris_core *core);
 	int (*raise_interrupt)(struct iris_core *core);
+	int (*clear_interrupt)(struct iris_core *core);
+	int (*watchdog)(struct iris_core *core, u32 intr_status);
 };
 
 int init_vpu(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
index 95bf223..a34d0ed 100644
--- a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
@@ -17,6 +17,8 @@
 #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_A2HSOFTINTCLR_IRIS3  (CPU_CS_BASE_OFFS_IRIS3 + 0x1C)
+
 /* HFI_CTRL_INIT */
 #define CPU_CS_SCIACMD_IRIS3        (CPU_CS_BASE_OFFS_IRIS3 + 0x48)
 
@@ -57,10 +59,19 @@
 #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 CTRL_INIT_IDLE_MSG_BMSK_IRIS3 \
+		CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3
+
+#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 CPU_IC_SOFTINT_IRIS3        (CPU_IC_BASE_OFFS_IRIS3 + 0x150)
 #define CPU_IC_SOFTINT_H2A_SHFT_IRIS3	0x0
 
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3  0x8
+
 static int setup_ucregion_memory_map_iris3(struct iris_core *core)
 {
 	int ret;
@@ -153,9 +164,42 @@ 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 int clear_interrupt_iris3(struct iris_core *core)
+{
+	u32 intr_status = 0, mask = 0;
+	int ret;
+
+	ret = read_register(core, WRAPPER_INTR_STATUS_IRIS3, &intr_status);
+	if (ret)
+		return ret;
+
+	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;
+
+	ret = write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS3, 1);
+
+	return ret;
+}
+
+static int watchdog_iris3(struct iris_core *core, u32 intr_status)
+{
+	if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3) {
+		dev_err(core->dev, "%s: received watchdog interrupt\n", __func__);
+		return -ETIME;
+	}
+
+	return 0;
+}
+
 static const struct vpu_ops iris3_ops = {
 	.boot_firmware = boot_firmware_iris3,
 	.raise_interrupt = raise_interrupt_iris3,
+	.clear_interrupt = clear_interrupt_iris3,
+	.watchdog = watchdog_iris3,
 };
 
 int init_iris3(struct iris_core *core)
