Browse Source

Merge "msm: camera: common: Add Minidump changes for NRT devices" into camera-kernel.lnx.5.0

Savita Patted 3 năm trước cách đây
mục cha
commit
946cfd80fe

+ 21 - 0
drivers/cam_core/cam_context.c

@@ -341,6 +341,27 @@ int cam_context_handle_crm_dump_req(struct cam_context *ctx,
 	return rc;
 }
 
+int cam_context_mini_dump_from_hw(struct cam_context *ctx,
+	void  *args)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context [id %d name:%s] is not ready", ctx->ctx_id,
+			ctx->dev_name);
+		return -EINVAL;
+	}
+
+	if ((ctx->state >= CAM_CTX_AVAILABLE) && (ctx->state < CAM_CTX_STATE_MAX)) {
+		if (ctx->state_machine[ctx->state].mini_dump_ops)
+			rc = ctx->state_machine[ctx->state].mini_dump_ops(ctx, args);
+		else
+			CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d",
+				ctx->dev_hdl, ctx->state);
+	}
+	return rc;
+}
+
 int cam_context_dump_pf_info(struct cam_context *ctx,
 	struct cam_smmu_pf_info *pf_info)
 {

+ 16 - 0
drivers/cam_core/cam_context.h

@@ -168,6 +168,7 @@ struct cam_ctx_crm_ops {
  * @dumpinfo_ops:          Function to be invoked for dumping any
  *                         context info
  * @recovery_ops:          Function to be invoked to try hardware recovery
+ * @mini_dump_ops:         Function for mini dump
  *
  */
 struct cam_ctx_ops {
@@ -177,6 +178,7 @@ struct cam_ctx_ops {
 	cam_hw_pagefault_cb_func     pagefault_ops;
 	cam_ctx_info_dump_cb_func    dumpinfo_ops;
 	cam_ctx_recovery_cb_func     recovery_ops;
+	cam_ctx_mini_dump_cb_func    mini_dump_ops;
 };
 
 /**
@@ -218,6 +220,7 @@ struct cam_ctx_ops {
  * @hw_updater_entry:      Hw update entry
  * @in_map_entries:        In map update entry
  * @out_map_entries:       Out map entry
+ * @mini dump cb:          Mini dump cb
  *
  */
 struct cam_context {
@@ -262,6 +265,7 @@ struct cam_context {
 	struct cam_hw_update_entry    *hw_update_entry;
 	struct cam_hw_fence_map_entry *in_map_entries;
 	struct cam_hw_fence_map_entry *out_map_entries;
+	cam_ctx_mini_dump_cb_func      mini_dump_cb;
 
 };
 
@@ -408,6 +412,18 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx,
 int cam_context_handle_crm_dump_req(struct cam_context *ctx,
 	struct cam_req_mgr_dump_info *dump);
 
+/**
+ * cam_context_mini_dump_from_hw()
+ *
+ * @brief:        Handle mini dump request command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @args:         Args to be passed
+ *
+ */
+int cam_context_mini_dump_from_hw(struct cam_context *ctx,
+	void  *args);
+
 /**
  * cam_context_dump_pf_info()
  *

+ 152 - 0
drivers/cam_core/cam_context_utils.c

@@ -615,6 +615,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
 	param.context_data = ctx;
 	param.ctx_id = ctx->ctx_id;
 	param.event_cb = ctx->irq_cb_intf;
+	param.mini_dump_cb = ctx->mini_dump_cb;
 	param.num_acq = cmd->num_resources;
 	param.acquire_info = cmd->resource_hdl;
 
@@ -1318,3 +1319,154 @@ err:
 
 	return 0;
 }
+
+static void __cam_context_req_mini_dump(struct cam_ctx_request *req,
+	uint8_t *start_addr, uint8_t *end_addr,
+	unsigned long *bytes_updated)
+{
+	struct cam_hw_req_mini_dump      *req_md;
+	struct cam_buf_io_cfg            *io_cfg;
+	struct cam_packet                *packet = NULL;
+	unsigned long                     bytes_written = 0;
+	unsigned long                     bytes_required = 0;
+
+	bytes_required = sizeof(*req_md);
+	if (start_addr + bytes_written + bytes_required > end_addr)
+		goto end;
+
+	req_md = (struct cam_hw_req_mini_dump *)start_addr;
+
+	req_md->num_fence_map_in = req->num_in_map_entries;
+	req_md->num_fence_map_out = req->num_out_map_entries;
+	req_md->num_in_acked = atomic_read(&req->num_in_acked);
+	req_md->num_out_acked = req->num_out_acked;
+	req_md->request_id = req->request_id;
+	bytes_written += bytes_required;
+
+	if (req->num_out_map_entries) {
+		bytes_required = sizeof(struct cam_hw_fence_map_entry) *
+					req->num_out_map_entries;
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		req_md->fence_map_out = (struct cam_hw_fence_map_entry *)
+				(start_addr + bytes_written);
+		memcpy(req_md->fence_map_out, req->out_map_entries, bytes_required);
+		req_md->num_fence_map_out = req->num_out_map_entries;
+		bytes_written += bytes_required;
+	}
+
+	if (req->num_in_map_entries) {
+		bytes_required = sizeof(struct cam_hw_fence_map_entry) *
+				    req->num_in_map_entries;
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		req_md->fence_map_in = (struct cam_hw_fence_map_entry *)
+				(start_addr + bytes_written);
+		memcpy(req_md->fence_map_in, req->in_map_entries, bytes_required);
+		req_md->num_fence_map_in = req->num_in_map_entries;
+		bytes_written += bytes_required;
+	}
+
+	packet = (struct cam_packet *)req->pf_data.packet;
+	if (packet && packet->num_io_configs) {
+		bytes_required = packet->num_io_configs * sizeof(struct cam_buf_io_cfg);
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload +
+			    packet->io_configs_offset / 4);
+		req_md->io_cfg = (struct cam_buf_io_cfg *)(start_addr + bytes_written);
+		memcpy(req_md->io_cfg, io_cfg, bytes_required);
+		bytes_written += bytes_required;
+		req_md->num_io_cfg = packet->num_io_configs;
+	}
+
+end:
+	*bytes_updated = bytes_written;
+}
+
+int cam_context_mini_dump(struct cam_context *ctx, void *args)
+{
+	struct cam_hw_mini_dump_info *md;
+	struct cam_ctx_request *req, *req_temp;
+	struct cam_hw_mini_dump_args *md_args;
+	uint8_t                      *start_addr;
+	uint8_t                      *end_addr;
+	unsigned long                 bytes_written = 0;
+	unsigned long                 bytes_updated = 0;
+
+	if (!ctx || !args) {
+		CAM_ERR(CAM_CTXT, "invalid params");
+		return -EINVAL;
+	}
+
+	md_args = (struct cam_hw_mini_dump_args *)args;
+	if (md_args->len < sizeof(*md)) {
+		md_args->bytes_written = 0;
+		CAM_ERR(CAM_CTXT, "Insufficient len %lu, bytes_written %lu", md_args->len,
+			md_args->bytes_written);
+		return 0;
+	}
+
+	start_addr = (uint8_t *)md_args->start_addr;
+	end_addr  = start_addr + md_args->len;
+	md = (struct cam_hw_mini_dump_info *)md_args->start_addr;
+	md->ctx_id = ctx->ctx_id;
+	md->last_flush_req = ctx->last_flush_req;
+	md->hw_mgr_ctx_id = ctx->hw_mgr_ctx_id;
+	md->dev_id = ctx->dev_id;
+	md->link_hdl = ctx->link_hdl;
+	md->state = ctx->state;
+	md->session_hdl = ctx->session_hdl;
+	md->dev_hdl = ctx->dev_hdl;
+	scnprintf(md->name, CAM_HW_MINI_DUMP_DEV_NAME_LEN, ctx->dev_name);
+	bytes_written += sizeof(*md);
+
+	if (!list_empty(&ctx->active_req_list)) {
+		md->active_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->active_list[md->active_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+
+	if (!list_empty(&ctx->wait_req_list)) {
+		md->wait_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->wait_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->wait_list[md->wait_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+
+	if (!list_empty(&ctx->pending_req_list)) {
+		md->pending_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->pending_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->pending_list[md->pending_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+end:
+	md_args->bytes_written = bytes_written;
+	CAM_INFO(CAM_CTXT, "Ctx %s bytes_written %lu", ctx->dev_name, md_args->bytes_written);
+	return 0;
+}

+ 1 - 0
drivers/cam_core/cam_context_utils.h

@@ -36,4 +36,5 @@ int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
 	struct cam_dump_req_cmd *cmd);
 size_t cam_context_parse_config_cmd(struct cam_context *ctx, struct cam_config_dev_cmd *cmd,
 	struct cam_packet **packet);
+int cam_context_mini_dump(struct cam_context *ctx, void *args);
 #endif /* _CAM_CONTEXT_UTILS_H_ */

+ 70 - 0
drivers/cam_core/cam_hw_mgr_intf.h

@@ -26,6 +26,9 @@
 /* Maximum reg dump cmd buffer entries in a context */
 #define CAM_REG_DUMP_MAX_BUF_ENTRIES        10
 
+/* max device name string length*/
+#define CAM_HW_MINI_DUMP_DEV_NAME_LEN       20
+
 /**
  * enum cam_context_dump_id -
  *              context dump type
@@ -415,6 +418,73 @@ struct cam_hw_mini_dump_args {
 	unsigned long     bytes_written;
 };
 
+/**
+ * struct cam_hw_req_mini_dump - Mini dump context req
+ *
+ * @fence_map_out:       Fence map out array
+ * @fence_map_in:        Fence map in array
+ * @io_cfg:              IO cfg.
+ * @request_id:          Request id
+ * @num_fence_map_in:    num of fence map in
+ * @num_fence_map_in:    num of fence map out
+ * @num_io_cfg:          num of io cfg
+ * @num_in_acked:        num in acked
+ * @num_out_acked:       num out acked
+ * @status:              Status
+ * @flushed:             whether request is flushed
+ *
+ */
+struct cam_hw_req_mini_dump {
+	struct cam_hw_fence_map_entry     *fence_map_out;
+	struct cam_hw_fence_map_entry     *fence_map_in;
+	struct cam_buf_io_cfg             *io_cfg;
+	uint64_t                           request_id;
+	uint16_t                           num_fence_map_in;
+	uint16_t                           num_fence_map_out;
+	uint16_t                           num_io_cfg;
+	uint16_t                           num_in_acked;
+	uint16_t                           num_out_acked;
+	uint8_t                            status;
+	uint8_t                            flushed;
+};
+
+/**
+ * struct cam_hw_mini_dump_info - Mini dump context info
+ *
+ * @active_list:          array of active req in context
+ * @wait_list:            array of  wait req in context
+ * @pending_list:         array of pending req in context
+ * @name:                 name of context
+ * @dev_id:               dev id.
+ * @last_flush_req:       last flushed request id
+ * @refcount:             kernel ref count
+ * @ctx_id:               Context id
+ * @session_hdl:          Session handle
+ * @link_hdl:             link handle
+ * @dev_hdl:              Dev hdl
+ * @state:                State of context
+ * @hw_mgr_ctx_id:        ctx id with hw mgr
+ *
+ */
+struct cam_hw_mini_dump_info {
+	struct   cam_hw_req_mini_dump   *active_list;
+	struct   cam_hw_req_mini_dump   *wait_list;
+	struct   cam_hw_req_mini_dump   *pending_list;
+	char                             name[CAM_HW_MINI_DUMP_DEV_NAME_LEN];
+	uint64_t                         dev_id;
+	uint32_t                         last_flush_req;
+	uint32_t                         refcount;
+	uint32_t                         ctx_id;
+	uint32_t                         active_cnt;
+	uint32_t                         pending_cnt;
+	uint32_t                         wait_cnt;
+	int32_t                          session_hdl;
+	int32_t                          link_hdl;
+	int32_t                          dev_hdl;
+	uint8_t                          state;
+	uint8_t                          hw_mgr_ctx_id;
+};
+
 /**
  * cam_hw_mgr_intf - HW manager interface
  *

+ 23 - 0
drivers/cam_icp/cam_icp_context.c

@@ -66,6 +66,25 @@ end:
 	return rc;
 }
 
+static int cam_icp_context_mini_dump(void *priv, void *args)
+{
+	int rc;
+	struct cam_context *ctx;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_ICP, "Invalid priv %pK args %pK", priv, args);
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)priv;
+	rc = cam_context_mini_dump(ctx, args);
+	if (rc)
+		CAM_ERR(CAM_ICP, "ctx [id: %u name: %s] Mini Dump failed rc %d", ctx->dev_name,
+			ctx->ctx_id, rc);
+
+	return rc;
+}
+
 static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -236,6 +255,7 @@ static struct cam_ctx_ops
 		},
 		.crm_ops = {},
 		.irq_ops = NULL,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Acquired */
 	{
@@ -249,6 +269,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = __cam_icp_handle_buf_done_in_ready,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Ready */
 	{
@@ -262,6 +283,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = __cam_icp_handle_buf_done_in_ready,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Flushed */
 	{
@@ -273,6 +295,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 };
 

+ 14 - 1
drivers/cam_icp/cam_icp_subdev.c

@@ -66,6 +66,19 @@ static void cam_icp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_info)
 		cam_context_dump_pf_info(&(node->ctx_list[i]), pf_info);
 }
 
+static void cam_icp_dev_mini_dump_cb(void *priv, void *args)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_ICP, "Invalid param priv: %pK args %pK", priv, args);
+		return;
+	}
+
+	ctx = (struct cam_context *)priv;
+	cam_context_mini_dump_from_hw(ctx, args);
+}
+
 static int cam_icp_subdev_open(struct v4l2_subdev *sd,
 	struct v4l2_subdev_fh *fh)
 {
@@ -187,7 +200,7 @@ static int cam_icp_component_bind(struct device *dev,
 	}
 
 	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf,
-		&iommu_hdl);
+		&iommu_hdl, cam_icp_dev_mini_dump_cb);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "ICP HW manager init failed: %d", rc);
 		goto hw_init_fail;

+ 20 - 0
drivers/cam_icp/fw_inc/hfi_intf.h

@@ -8,6 +8,9 @@
 
 #include <linux/types.h>
 
+#define HFI_CMD_Q_MINI_DUMP_SIZE_IN_BYTES      4096
+#define HFI_MSG_Q_MINI_DUMP_SIZE_IN_BYTES      4096
+
 /**
  * struct hfi_mem
  * @len: length of memory
@@ -61,6 +64,19 @@ struct hfi_ops {
 	void __iomem *(*iface_addr)(void *data);
 };
 
+/**
+ * struct hfi_mini_dump_info
+ * @cmd_q: cmd queue
+ * @msg_q: msg queue
+ * @msg_q_state: msg queue state
+ * @cmd_q_state: cmd queue state
+ */
+struct hfi_mini_dump_info {
+	uint32_t       cmd_q[HFI_CMD_Q_MINI_DUMP_SIZE_IN_BYTES];
+	uint32_t       msg_q[HFI_MSG_Q_MINI_DUMP_SIZE_IN_BYTES];
+	bool           msg_q_state;
+	bool           cmd_q_state;
+};
 /**
  * hfi_write_cmd() - function for hfi write
  * @cmd_ptr: pointer to command data for hfi write
@@ -163,5 +179,9 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem);
  */
 void cam_hfi_queue_dump(void);
 
+/**
+ * cam_hfi_mini_dump() - utility function for mini dump
+ */
+void cam_hfi_mini_dump(struct hfi_mini_dump_info *dst);
 
 #endif /* _HFI_INTF_H_ */

+ 26 - 0
drivers/cam_icp/hfi.c

@@ -87,6 +87,32 @@ static void hfi_queue_dump(uint32_t *dwords, int count)
 			rows * 4, dwords[0], dwords[1], dwords[2]);
 }
 
+void cam_hfi_mini_dump(struct hfi_mini_dump_info *dst)
+{
+	struct hfi_mem_info *hfi_mem = &g_hfi->map;
+	struct hfi_qtbl *qtbl;
+	struct hfi_q_hdr *q_hdr;
+	uint32_t *dwords;
+	int num_dwords;
+
+	if (!hfi_mem) {
+		CAM_ERR(CAM_HFI, "hfi mem info NULL... unable to dump queues");
+		return;
+	}
+
+	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+	q_hdr = &qtbl->q_hdr[Q_CMD];
+	dwords = (uint32_t *)hfi_mem->cmd_q.kva;
+	num_dwords = ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	memcpy(dst->cmd_q, dwords, ICP_CMD_Q_SIZE_IN_BYTES);
+
+	q_hdr = &qtbl->q_hdr[Q_MSG];
+	dwords = (uint32_t *)hfi_mem->msg_q.kva;
+	memcpy(dst->msg_q, dwords, ICP_CMD_Q_SIZE_IN_BYTES);
+	dst->msg_q_state = g_hfi->msg_q_state;
+	dst->cmd_q_state = g_hfi->cmd_q_state;
+}
+
 void cam_hfi_queue_dump(void)
 {
 	struct hfi_mem_info *hfi_mem = &g_hfi->map;

+ 38 - 0
drivers/cam_icp/icp_hw/a5_hw/a5_core.c

@@ -178,6 +178,37 @@ static int cam_a5_fw_dump(
 	return 0;
 }
 
+static int cam_a5_fw_mini_dump(
+	struct cam_icp_hw_dump_args    *dump_args,
+	struct cam_a5_device_core_info *core_info)
+{
+	u8                         *dest;
+	u8                         *src;
+
+	if (!core_info || !dump_args) {
+		CAM_ERR(CAM_ICP, "invalid params %pK %pK", core_info, dump_args);
+		return -EINVAL;
+	}
+
+	if (!core_info->fw_kva_addr || !dump_args->cpu_addr) {
+		CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", core_info->fw_kva_addr,
+			dump_args->cpu_addr);
+		return -EINVAL;
+	}
+
+	if (dump_args->buf_len < core_info->fw_buf_len) {
+		CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
+			dump_args->buf_len, core_info->fw_buf_len);
+		return -ENOSPC;
+	}
+
+	dest = (u8 *)dump_args->cpu_addr;
+	src = (u8 *)core_info->fw_kva_addr;
+	memcpy_fromio(dest, src, core_info->fw_buf_len);
+	dump_args->offset = core_info->fw_buf_len;
+	return 0;
+}
+
 int cam_a5_init_hw(void *device_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
@@ -706,6 +737,13 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_a5_fw_dump(dump_args, core_info);
 		break;
 	}
+
+	case CAM_ICP_CMD_HW_MINI_DUMP: {
+		struct cam_icp_hw_dump_args *dump_args = cmd_args;
+
+		rc = cam_a5_fw_mini_dump(dump_args, core_info);
+		break;
+	}
 	default:
 		break;
 	}

+ 130 - 1
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -3711,6 +3711,132 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)
 	return 0;
 }
 
+static unsigned long cam_icp_hw_mgr_mini_dump_cb(void *dst, unsigned long len)
+{
+	struct cam_icp_hw_mini_dump_info   *md;
+	struct cam_icp_hw_ctx_mini_dump    *ctx_md;
+	struct cam_icp_hw_ctx_data         *ctx;
+	struct cam_icp_hw_mgr              *hw_mgr;
+	struct cam_hw_mini_dump_args        hw_dump_args;
+	struct cam_icp_hw_dump_args         icp_dump_args;
+	struct cam_hw_intf                 *icp_dev_intf = NULL;
+	uint32_t                            i = 0, j = 0;
+	unsigned long                       dumped_len = 0;
+	unsigned long                       remain_len = len;
+	int                                 rc = 0;
+
+	if (!dst || len < sizeof(*md)) {
+		CAM_ERR(CAM_ICP, "Invalid params dst %pk len %lu", dst, len);
+		return 0;
+	}
+
+	md = (struct cam_icp_hw_mini_dump_info *)dst;
+	md->num_context = 0;
+	hw_mgr = &icp_hw_mgr;
+	cam_hfi_mini_dump(&md->hfi_info);
+	memcpy(&md->hfi_mem_info, &hw_mgr->hfi_mem,
+		sizeof(struct icp_hfi_mem_info));
+	md->recovery = atomic_read(&hw_mgr->recovery);
+	md->icp_booted = hw_mgr->icp_booted;
+	md->icp_resumed = hw_mgr->icp_resumed;
+	md->ipe_clk_state = hw_mgr->ipe_clk_state;
+	md->ipe_clk_state = hw_mgr->ipe_clk_state;
+	md->bps_clk_state = hw_mgr->bps_clk_state;
+	md->disable_ubwc_comp = hw_mgr->disable_ubwc_comp;
+	md->ipe0_enable = hw_mgr->ipe0_enable;
+	md->ipe1_enable = hw_mgr->ipe1_enable;
+	md->bps_enable = hw_mgr->bps_enable;
+	md->icp_pc_flag = hw_mgr->icp_pc_flag;
+	md->ipe_bps_pc_flag = hw_mgr->ipe_bps_pc_flag;
+	md->icp_use_pil = hw_mgr->icp_use_pil;
+	dumped_len += sizeof(*md);
+	remain_len = len -  dumped_len;
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx = &hw_mgr->ctx_data[i];
+		if (ctx->state == CAM_ICP_CTX_STATE_FREE ||
+			ctx->state == CAM_ICP_CTX_STATE_RELEASE)
+			continue;
+
+		if (remain_len < sizeof(*ctx_md))
+			goto end;
+
+		md->num_context++;
+		ctx_md = (struct cam_icp_hw_ctx_mini_dump *)
+			    ((uint8_t *)dst + dumped_len);
+		md->ctx[i] = ctx_md;
+		ctx_md->state = ctx->state;
+		ctx_md->ctx_id = ctx->ctx_id;
+		memcpy(ctx_md->ctx_id_string, ctx->ctx_id_string,
+			strlen(ctx->ctx_id_string));
+		if (ctx->icp_dev_acquire_info) {
+			ctx_md->acquire.secure_mode =
+				ctx->icp_dev_acquire_info->secure_mode;
+			ctx_md->acquire.dev_type =
+				ctx->icp_dev_acquire_info->dev_type;
+			ctx_md->acquire.num_out_res =
+				ctx->icp_dev_acquire_info->num_out_res;
+			memcpy(&ctx_md->acquire.in_res,
+				&ctx->icp_dev_acquire_info->in_res,
+				sizeof(struct cam_icp_res_info));
+			memcpy(ctx_md->acquire.out_res,
+				ctx->icp_dev_acquire_info->out_res,
+				sizeof(ctx->icp_dev_acquire_info->out_res));
+		} else {
+			memset(&ctx_md->acquire, 0,
+				sizeof(struct cam_icp_mini_dump_acquire_info));
+		}
+
+		memcpy(ctx_md->hfi_frame.request_id, ctx->hfi_frame_process.request_id,
+			sizeof(ctx->hfi_frame_process.request_id));
+		memcpy(ctx_md->hfi_frame.in_resource, ctx->hfi_frame_process.in_resource,
+			sizeof(ctx->hfi_frame_process.in_resource));
+		memcpy(ctx_md->hfi_frame.submit_timestamp,
+			ctx->hfi_frame_process.submit_timestamp,
+			sizeof(ctx->hfi_frame_process.submit_timestamp));
+		memcpy(ctx_md->hfi_frame.num_out_res, ctx->hfi_frame_process.num_out_resources,
+			sizeof(ctx->hfi_frame_process.num_out_resources));
+		memcpy(ctx_md->hfi_frame.out_res, ctx->hfi_frame_process.out_resource,
+			sizeof(ctx->hfi_frame_process.out_resource));
+		for (j = 0; j < CAM_FRAME_CMD_MAX; j++) {
+			ctx_md->hfi_frame.fw_process_flag[j] =
+				ctx->hfi_frame_process.fw_process_flag[j];
+		}
+
+		dumped_len += sizeof(*ctx_md);
+		remain_len = len - dumped_len;
+		hw_dump_args.len = remain_len;
+		hw_dump_args.bytes_written = 0;
+		hw_dump_args.start_addr = (void *)((uint8_t *)dst + dumped_len);
+		hw_mgr->mini_dump_cb(ctx->context_priv, &hw_dump_args);
+		if (dumped_len + hw_dump_args.bytes_written >= len)
+			goto end;
+
+		ctx_md->hw_ctx = hw_dump_args.start_addr;
+		dumped_len += hw_dump_args.bytes_written;
+		remain_len = len - dumped_len;
+	}
+
+	/* Dump fw image */
+	if (!hw_mgr->icp_use_pil) {
+		icp_dump_args.cpu_addr = (uintptr_t)((uint8_t *)dst + dumped_len);
+		icp_dump_args.offset = 0;
+		icp_dump_args.buf_len = remain_len;
+		icp_dev_intf = hw_mgr->icp_dev_intf;
+		rc = icp_dev_intf->hw_ops.process_cmd(
+			icp_dev_intf->hw_priv,
+			CAM_ICP_CMD_HW_MINI_DUMP, &icp_dump_args,
+			sizeof(struct cam_icp_hw_dump_args));
+		if (rc)
+			goto end;
+
+		dumped_len += icp_dump_args.offset;
+		md->fw_img = (void *)icp_dump_args.cpu_addr;
+		remain_len = len - dumped_len;
+	}
+end:
+	return dumped_len;
+}
+
 static void cam_icp_mgr_device_deinit(struct cam_icp_hw_mgr *hw_mgr)
 {
 	struct cam_hw_intf *icp_dev_intf = NULL;
@@ -6351,7 +6477,7 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 }
 
 int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
-	int *iommu_hdl)
+	int *iommu_hdl, cam_icp_mini_dump_cb mini_dump_cb)
 {
 	int i, rc = 0;
 	struct cam_hw_mgr_intf *hw_mgr_intf;
@@ -6380,6 +6506,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump;
 
 	icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE;
+	icp_hw_mgr.mini_dump_cb = mini_dump_cb;
 	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
 	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
 
@@ -6445,6 +6572,8 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 		*iommu_hdl = icp_hw_mgr.iommu_hdl;
 
 	init_completion(&icp_hw_mgr.icp_complete);
+	cam_common_register_mini_dump_cb(
+		cam_icp_hw_mgr_mini_dump_cb, "cam_icp");
 	return rc;
 
 icp_wq_create_failed:

+ 98 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h

@@ -14,6 +14,7 @@
 #include "cam_hw_intf.h"
 #include "cam_a5_hw_intf.h"
 #include "hfi_session_defs.h"
+#include "hfi_intf.h"
 #include "cam_req_mgr_workq.h"
 #include "cam_mem_mgr.h"
 #include "cam_smmu_api.h"
@@ -75,6 +76,8 @@
  */
 #define CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD   300000
 
+struct hfi_mini_dump_info;
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
@@ -321,6 +324,7 @@ struct cam_icp_clk_info {
  * @devices: Devices of ICP hardware manager
  * @ctx_data: Context data
  * @icp_caps: ICP capabilities
+ * @mini_dump_cb: Mini dump cb
  * @icp_booted: Processor is booted i.e. firmware loaded
  * @icp_resumed: Processor is powered on
  * @iommu_hdl: Non secure IOMMU handle
@@ -372,6 +376,7 @@ struct cam_icp_hw_mgr {
 	struct cam_hw_intf **devices[CAM_ICP_DEV_MAX];
 	struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX];
 	struct cam_icp_query_cap_cmd icp_caps;
+	cam_icp_mini_dump_cb mini_dump_cb;
 
 	bool icp_booted;
 	bool icp_resumed;
@@ -415,6 +420,99 @@ struct cam_icp_hw_mgr {
 	atomic_t recovery;
 };
 
+/**
+ * struct cam_icp_mini_dump_acquire_info - ICP mini dump device info
+ *
+ * @in_res: resource info used for clock and bandwidth calculation
+ * @out_res: output resource
+ * @num_out_res: number of output resources
+ * @dev_type: device type (IPE_RT/IPE_NON_RT/BPS)
+ * @secure_mode: camera mode (secure/non secure)
+ */
+struct cam_icp_mini_dump_acquire_info {
+	struct cam_icp_res_info out_res[ICP_MAX_OUTPUT_SUPPORTED];
+	struct cam_icp_res_info in_res;
+	uint16_t                num_out_res;
+	uint8_t                 dev_type;
+	uint8_t                 secure_mode;
+};
+
+/**
+ * struct hfi_frame_process_info
+ * @request_id: Request id list
+ * @num_out_res: Number of out syncs
+ * @out_res: Out sync info
+ * @in_resource: In sync info
+ * @submit_timestamp: Submit timestamp to hw
+ * @fw_process_flag: Frame process flag
+ */
+struct  hfi_frame_mini_dump_info {
+	uint64_t                              request_id[CAM_FRAME_CMD_MAX];
+	uint32_t                              num_out_res[CAM_FRAME_CMD_MAX];
+	uint32_t                              out_res[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+	uint32_t                              in_resource[CAM_FRAME_CMD_MAX];
+	ktime_t                               submit_timestamp[CAM_FRAME_CMD_MAX];
+	uint8_t                               fw_process_flag[CAM_FRAME_CMD_MAX];
+};
+
+/**
+ * struct cam_icp_hw_ctx_mini_dump
+ * @acquire: Acquire device info
+ * @hfi_frame: Frame  command
+ * @hw_ctx: Context private data
+ * @state: context state
+ * @ctx_id_string: Context id string
+ * @ctx_id: Context Id
+ */
+struct cam_icp_hw_ctx_mini_dump {
+	struct cam_icp_mini_dump_acquire_info acquire;
+	struct hfi_frame_mini_dump_info       hfi_frame;
+	void                                 *hw_ctx;
+	char                                  ctx_id_string[128];
+	uint8_t                               state;
+	uint8_t                               ctx_id;
+};
+
+/**
+ * struct cam_icp_hw_mini_dump_info
+ *
+ * @ctx: Context for minidump
+ * @hfi_info: hfi info
+ * @hfi_mem_info: hfi mem info
+ * @fw_img: FW image
+ * @recovery: To indicate if recovery is on
+ * @icp_booted: Indicate if ICP is booted
+ * @icp_resumed: Indicate if ICP is resumed
+ * @ipe_clk_state: IPE Clk state
+ * @bps_clk_state: BPS clk state
+ * @disable_ubwc_comp: Indicate if ubws comp is disabled
+ * @ipe0_enable: Is IPE0 enabled
+ * @ipe1_enable: Is IPE1 enabled
+ * @bps_enable:  Is BPS enabled
+ * @icp_pc_flag: Is ICP PC enabled
+ * @ipe_bps_pc_flag: Is IPE BPS PC enabled
+ * @icp_use_pil: Is PIL used
+ */
+struct cam_icp_hw_mini_dump_info {
+	struct cam_icp_hw_ctx_mini_dump   *ctx[CAM_ICP_CTX_MAX];
+	struct hfi_mini_dump_info          hfi_info;
+	struct icp_hfi_mem_info            hfi_mem_info;
+	void                              *fw_img;
+	uint32_t                           recovery;
+	uint32_t                           num_context;
+	bool                               icp_booted;
+	bool                               icp_resumed;
+	bool                               ipe_clk_state;
+	bool                               bps_clk_state;
+	bool                               disable_ubwc_comp;
+	bool                               ipe0_enable;
+	bool                               ipe1_enable;
+	bool                               bps_enable;
+	bool                               icp_pc_flag;
+	bool                               ipe_bps_pc_flag;
+	bool                               icp_use_pil;
+};
+
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
 static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args);
 static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr);

+ 1 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h

@@ -42,6 +42,7 @@ enum cam_icp_cmd_type {
 	CAM_ICP_CMD_PC_PREP,
 	CAM_ICP_CMD_CLK_UPDATE,
 	CAM_ICP_CMD_HW_DUMP,
+	CAM_ICP_CMD_HW_MINI_DUMP,
 	CAM_ICP_CMD_MAX,
 };
 

+ 5 - 1
drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h

@@ -30,8 +30,12 @@
 #define CAM_ICP_DUMP_TAG_MAX_LEN 32
 #define CAM_ICP_DUMP_NUM_WORDS   5
 
+typedef void(*cam_icp_mini_dump_cb)(void *priv,
+	void *args);
+
 int cam_icp_hw_mgr_init(struct device_node *of_node,
-	uint64_t *hw_mgr_hdl, int *iommu_hdl);
+	uint64_t *hw_mgr_hdl, int *iommu_hdl,
+	cam_icp_mini_dump_cb mini_dump_cb);
 
 void cam_icp_hw_mgr_deinit(void);
 

+ 36 - 0
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c

@@ -777,6 +777,38 @@ static int __cam_lx7_update_clk_rate(
 	return rc;
 }
 
+static int __cam_lx7_fw_mini_dump(
+	struct cam_lx7_core_info       *core_info,
+	struct cam_icp_hw_dump_args    *args)
+{
+	u8                          *dest;
+	u8                          *src;
+	struct cam_icp_hw_dump_args *dump_args = args;
+
+	if (!core_info || !dump_args) {
+		CAM_ERR(CAM_ICP, "invalid params %pK %pK", core_info, dump_args);
+		return -EINVAL;
+	}
+
+	if (!core_info->fw_params.fw_kva_addr || !dump_args->cpu_addr) {
+		CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx",
+		    core_info->fw_params.fw_kva_addr, dump_args->cpu_addr);
+		return -EINVAL;
+	}
+
+	if (dump_args->buf_len < core_info->fw_params.fw_buf_len) {
+		CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
+			dump_args->buf_len, core_info->fw_params.fw_buf_len);
+		return -ENOSPC;
+	}
+
+	dest = (u8 *)dump_args->cpu_addr;
+	src = (u8 *)core_info->fw_params.fw_kva_addr;
+	memcpy_fromio(dest, src, core_info->fw_params.fw_buf_len);
+	dump_args->offset = core_info->fw_params.fw_buf_len;
+	return 0;
+}
+
 int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
 			void *args, uint32_t arg_size)
 {
@@ -829,6 +861,10 @@ int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
 		/* Not supported for lx7 */
 		rc = 0;
 		break;
+	case CAM_ICP_CMD_HW_MINI_DUMP: {
+		rc = __cam_lx7_fw_mini_dump(lx7_info->core_info, args);
+		break;
+	}
 	default:
 		CAM_ERR(CAM_ICP, "invalid command type=%u", cmd_type);
 		break;

+ 20 - 0
drivers/cam_jpeg/cam_jpeg_context.c

@@ -56,6 +56,24 @@ static int cam_jpeg_context_dump_active_request(void *data,
 	return rc;
 }
 
+static int cam_jpeg_context_mini_dump(void *priv, void *args)
+{
+	int rc;
+	struct cam_context *ctx;
+
+	if (!priv || args) {
+		CAM_ERR(CAM_ICP, "Invalid param priv %pK args %pK", priv, args);
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)priv;
+	rc = cam_context_mini_dump(ctx, args);
+	if (rc)
+		CAM_ERR(CAM_JPEG, "Mini Dump failed %d", rc);
+
+	return rc;
+}
+
 static int __cam_jpeg_ctx_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -151,6 +169,7 @@ static struct cam_ctx_ops
 		},
 		.crm_ops = { },
 		.irq_ops = NULL,
+		.mini_dump_ops = cam_jpeg_context_mini_dump,
 	},
 	/* Acquired */
 	{
@@ -164,6 +183,7 @@ static struct cam_ctx_ops
 		.crm_ops = { },
 		.irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired,
 		.pagefault_ops = cam_jpeg_context_dump_active_request,
+		.mini_dump_ops = cam_jpeg_context_mini_dump,
 	},
 	/* Ready */
 	{

+ 15 - 1
drivers/cam_jpeg/cam_jpeg_dev.c

@@ -38,6 +38,19 @@ static void cam_jpeg_dev_iommu_fault_handler(
 		cam_context_dump_pf_info(&(node->ctx_list[i]), pf_info);
 }
 
+static void cam_jpeg_dev_mini_dump_cb(void *priv, void *args)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid param priv %pK %pK args", priv, args);
+		return;
+	}
+
+	ctx = (struct cam_context *)priv;
+	cam_context_mini_dump_from_hw(ctx, args);
+}
+
 static const struct of_device_id cam_jpeg_dt_match[] = {
 	{
 		.compatible = "qcom,cam-jpeg"
@@ -123,7 +136,8 @@ static int cam_jpeg_dev_component_bind(struct device *dev,
 	node = (struct cam_node *)g_jpeg_dev.sd.token;
 
 	rc = cam_jpeg_hw_mgr_init(pdev->dev.of_node,
-		(uint64_t *)&hw_mgr_intf, &iommu_hdl);
+		(uint64_t *)&hw_mgr_intf, &iommu_hdl,
+		cam_jpeg_dev_mini_dump_cb);
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "Can not initialize JPEG HWmanager %d", rc);
 		goto unregister;

+ 81 - 2
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c

@@ -1421,7 +1421,7 @@ static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	mutex_unlock(&ctx_data->ctx_mutex);
 
 	hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
-
+	hw_mgr->ctx_data[ctx_id].mini_dump_cb = args->mini_dump_cb;
 
 	if (copy_to_user((void __user *)args->acquire_info,
 		&jpeg_dev_acquire_info,
@@ -1971,8 +1971,83 @@ static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 	return rc;
 }
 
+static unsigned long cam_jpeg_hw_mgr_mini_dump_cb(void *dst, unsigned long len)
+{
+	struct cam_jpeg_hw_mini_dump_req *md_req;
+	struct cam_jpeg_hw_mgr_mini_dump *md;
+	struct cam_jpeg_hw_ctx_mini_dump *ctx_md;
+	struct cam_jpeg_hw_ctx_data      *ctx;
+	struct cam_jpeg_hw_mgr           *hw_mgr;
+	struct cam_jpeg_hw_cfg_req       *req;
+	struct cam_hw_mini_dump_args      hw_dump_args;
+	uint32_t                          dev_type;
+	uint32_t                          i = 0;
+	unsigned long                     dumped_len = 0;
+	unsigned long                     remain_len = len;
+
+	if (!dst || len < sizeof(*md)) {
+		CAM_ERR(CAM_JPEG, "Invalid params dst %pk len %lu", dst, len);
+		return 0;
+	}
+
+	md = (struct cam_jpeg_hw_mgr_mini_dump *)dst;
+	md->num_context = 0;
+	hw_mgr = &g_jpeg_hw_mgr;
+	for (i = 0; i < CAM_JPEG_RES_TYPE_MAX; i++) {
+		if (hw_mgr->devices[i][0]->hw_ops.process_cmd) {
+			hw_mgr->devices[i][0]->hw_ops.process_cmd(
+				hw_mgr->devices[i][0]->hw_priv,
+				CAM_JPEG_CMD_MINI_DUMP,
+				&md->core[i],
+				sizeof(struct cam_jpeg_mini_dump_core_info));
+		}
+	}
+
+	dumped_len += sizeof(*md);
+	remain_len = len - dumped_len;
+	for (i = 0; i < CAM_JPEG_CTX_MAX; i++) {
+		ctx = &hw_mgr->ctx_data[i];
+		if (!ctx->in_use)
+			continue;
+
+		if (remain_len < sizeof(*ctx_md))
+			goto end;
+
+		md->num_context++;
+		ctx_md = (struct cam_jpeg_hw_ctx_mini_dump *)
+			    ((uint8_t *)dst + dumped_len);
+		md->ctx[i] = ctx_md;
+		ctx_md->in_use  = ctx->in_use;
+		memcpy(&ctx_md->acquire_info, &ctx->jpeg_dev_acquire_info,
+			sizeof(struct cam_jpeg_acquire_dev_info));
+		dev_type = ctx->jpeg_dev_acquire_info.dev_type;
+		req = hw_mgr->dev_hw_cfg_args[dev_type][0];
+		if (req) {
+			md_req = &md->cfg_req[dev_type];
+			memcpy(&md_req->submit_timestamp, &req->submit_timestamp,
+				sizeof(ktime_t));
+			md_req->req_id = req->req_id;
+			md_req->dev_type = req->dev_type;
+			md_req->num_hw_entry_processed = req->num_hw_entry_processed;
+		}
+
+		hw_dump_args.len = remain_len;
+		hw_dump_args.bytes_written = 0;
+		hw_dump_args.start_addr = (void *)((uint8_t *)dst + dumped_len);
+		hw_mgr->mini_dump_cb(ctx->context_priv, &hw_dump_args);
+		if (dumped_len + hw_dump_args.bytes_written >= len)
+			goto end;
+
+		dumped_len += hw_dump_args.bytes_written;
+		remain_len = len - dumped_len;
+	}
+
+end:
+	return dumped_len;
+}
+
 int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
-	int *iommu_hdl)
+	int *iommu_hdl, cam_jpeg_mini_dump_cb mini_dump_cb)
 {
 	int i, rc;
 	uint32_t num_dev;
@@ -2048,6 +2123,8 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.incr  = 0;
 	g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.reserved = 0;
 
+	g_jpeg_hw_mgr.mini_dump_cb = mini_dump_cb;
+
 	rc = cam_jpeg_setup_workqs();
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "setup work qs failed  %d", rc);
@@ -2057,6 +2134,8 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	if (iommu_hdl)
 		*iommu_hdl = g_jpeg_hw_mgr.iommu_hdl;
 
+	cam_common_register_mini_dump_cb(cam_jpeg_hw_mgr_mini_dump_cb, "CAM_JPEG");
+
 	return rc;
 
 cdm_iommu_failed:

+ 46 - 0
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h

@@ -103,6 +103,7 @@ struct cam_jpeg_hw_cfg_req {
  * @in_use: Flag for context usage
  * @wait_complete: Completion info
  * @cdm_cmd: Cdm cmd submitted for that context.
+ * @mini_dump_cb: Mini dump cb
  */
 struct cam_jpeg_hw_ctx_data {
 	void *context_priv;
@@ -112,6 +113,7 @@ struct cam_jpeg_hw_ctx_data {
 	bool in_use;
 	struct completion wait_complete;
 	struct cam_cdm_bl_request *cdm_cmd;
+	cam_ctx_mini_dump_cb_func      mini_dump_cb;
 };
 
 /**
@@ -138,6 +140,7 @@ struct cam_jpeg_hw_ctx_data {
  * @free_req_list: Free nodes for above list
  * @req_list: Nodes of hw update list
  * @num_pid: num of pids supported in the device
+ * @mini_dump_cb: Mini dump cb
  */
 struct cam_jpeg_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -167,6 +170,49 @@ struct cam_jpeg_hw_mgr {
 	struct list_head free_req_list;
 	struct cam_jpeg_hw_cfg_req req_list[CAM_JPEG_HW_CFG_Q_MAX];
 	uint32_t num_pid[CAM_JPEG_DEV_TYPE_MAX];
+	cam_jpeg_mini_dump_cb      mini_dump_cb;
 };
 
+/**
+ * struct cam_jpeg_hw_mini_dump_req
+ *
+ * @submit_timestamp:        Time stamp of request submit
+ * @req_id:                  Request Id
+ * @dev_type:                Dev type
+ * @num_hw_entry_processed:  Num of hw entry processed
+ */
+struct cam_jpeg_hw_mini_dump_req {
+	ktime_t    submit_timestamp;
+	uintptr_t  req_id;
+	uint32_t   dev_type;
+	uint32_t   num_hw_entry_processed;
+};
+
+/**
+ * struct cam_jpeg_hw_ctx_mini_dump
+ *
+ * @acquire_info:        Acquire info
+ * @hw_ctx:              hw context info
+ * @in_use:              flag to indicate if in use
+ */
+struct cam_jpeg_hw_ctx_mini_dump {
+	struct cam_jpeg_acquire_dev_info        acquire_info;
+	struct cam_hw_mini_dump_info            hw_ctx;
+	bool                                    in_use;
+};
+
+/**
+ * struct cam_jpeg_hw_mgr_mini_dump
+ *
+ * @ctx:               Context info array
+ * @cfg_req:           Cfg req
+ * @core:              core info
+ * @num_context:       Num of context
+ */
+struct cam_jpeg_hw_mgr_mini_dump {
+	struct cam_jpeg_hw_ctx_mini_dump      *ctx[CAM_JPEG_CTX_MAX];
+	struct cam_jpeg_hw_mini_dump_req       cfg_req[CAM_JPEG_DEV_TYPE_MAX];
+	struct cam_jpeg_mini_dump_core_info    core[CAM_JPEG_RES_TYPE_MAX];
+	uint32_t                               num_context;
+};
 #endif /* CAM_JPEG_HW_MGR_H */

+ 12 - 0
drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h

@@ -56,12 +56,24 @@ struct cam_jpeg_match_pid_args {
 	uint32_t    match_res;
 };
 
+struct cam_jpeg_mini_dump_core_info {
+	uint32_t           framedone;
+	uint32_t           resetdone;
+	uint32_t           iserror;
+	uint32_t           stopdone;
+	uint32_t           open_count;
+	int32_t            ref_count;
+	uint32_t           core_state;
+	uint32_t           hw_state;
+};
+
 enum cam_jpeg_cmd_type {
 	CAM_JPEG_CMD_CDM_CFG,
 	CAM_JPEG_CMD_SET_IRQ_CB,
 	CAM_JPEG_CMD_HW_DUMP,
 	CAM_JPEG_CMD_GET_NUM_PID,
 	CAM_JPEG_CMD_MATCH_PID_MID,
+	CAM_JPEG_CMD_MINI_DUMP,
 	CAM_JPEG_CMD_MAX,
 };
 

+ 4 - 1
drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h

@@ -33,7 +33,10 @@ struct cam_jpeg_request_data {
 	uint32_t                            thumbnail_threshold_size;
 };
 
+typedef void (*cam_jpeg_mini_dump_cb)(void *priv, void *dst);
+
 int cam_jpeg_hw_mgr_init(struct device_node *of_node,
-	uint64_t *hw_mgr_hdl, int *iommu_hdl);
+	uint64_t *hw_mgr_hdl, int *iommu_hdl,
+	cam_jpeg_mini_dump_cb mini_dump_cb);
 
 #endif /* CAM_JPEG_HW_MGR_INTF_H */

+ 29 - 0
drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c

@@ -369,6 +369,32 @@ int cam_jpeg_dma_stop_hw(void *data,
 	return 0;
 }
 
+static int  cam_jpeg_dma_mini_dump(struct cam_hw_info *dev, void *args) {
+
+	struct cam_jpeg_mini_dump_core_info *md;
+	struct cam_jpeg_dma_device_hw_info   *hw_info;
+	struct cam_jpeg_dma_device_core_info *core_info;
+
+	if (!dev || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid params dev %pK args %pK", dev, args);
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_jpeg_dma_device_core_info *)dev->core_info;
+	hw_info = core_info->jpeg_dma_hw_info;
+	md = (struct cam_jpeg_mini_dump_core_info *)args;
+
+	md->framedone = hw_info->int_status.framedone;
+	md->resetdone = hw_info->int_status.resetdone;
+	md->iserror = hw_info->int_status.iserror;
+	md->stopdone = hw_info->int_status.stopdone;
+	md->open_count = dev->open_count;
+	md->hw_state = dev->hw_state;
+	md->ref_count = core_info->ref_count;
+	md->core_state = core_info->core_state;
+	return 0;
+}
+
 int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -456,6 +482,9 @@ int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type,
 				match_pid_mid->pid_match_found = false;
 		}
 
+		break;
+	case CAM_JPEG_CMD_MINI_DUMP:
+		rc = cam_jpeg_dma_mini_dump(jpeg_dma_dev, cmd_args);
 		break;
 	default:
 		rc = -EINVAL;

+ 31 - 0
drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c

@@ -496,6 +496,32 @@ int cam_jpeg_enc_hw_dump(
 	return 0;
 }
 
+static int  cam_jpeg_enc_mini_dump(struct cam_hw_info *dev, void *args) {
+
+	struct cam_jpeg_mini_dump_core_info *md;
+	struct cam_jpeg_enc_device_hw_info   *hw_info;
+	struct cam_jpeg_enc_device_core_info *core_info;
+
+	if (!dev || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid params priv %pK args %pK", dev, args);
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_jpeg_enc_device_core_info *)dev->core_info;
+	hw_info = core_info->jpeg_enc_hw_info;
+	md = (struct cam_jpeg_mini_dump_core_info *)args;
+
+	md->framedone = hw_info->int_status.framedone;
+	md->resetdone = hw_info->int_status.resetdone;
+	md->iserror = hw_info->int_status.iserror;
+	md->stopdone = hw_info->int_status.stopdone;
+	md->open_count = dev->open_count;
+	md->hw_state = dev->hw_state;
+	md->ref_count = core_info->ref_count;
+	md->core_state = core_info->core_state;
+	return 0;
+}
+
 int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -590,6 +616,11 @@ int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type,
 		}
 
 		break;
+	case CAM_JPEG_CMD_MINI_DUMP:
+	{
+		rc = cam_jpeg_enc_mini_dump(jpeg_enc_dev, cmd_args);
+		break;
+	}
 	default:
 		rc = -EINVAL;
 		break;