Quellcode durchsuchen

Merge "msm: camera: isp: LDAR Dump ISP information" into camera-kernel.lnx.4.0

Camera Software Integration vor 5 Jahren
Ursprung
Commit
b52a99ab63

+ 168 - 0
drivers/cam_cdm/cam_cdm_util.c

@@ -823,3 +823,171 @@ void cam_cdm_util_dump_cmd_buf(
 		}
 	} while (buf_now <= cmd_buf_end);
 }
+
+static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2(
+	uint32_t                         *cmd_buf_addr,
+	struct cam_cdm_cmd_buf_dump_info *dump_info)
+{
+	int                             i;
+	long                            ret;
+	uint8_t                        *dst;
+	size_t                          remain_len;
+	uint32_t                       *temp_ptr = cmd_buf_addr;
+	uint32_t                       *addr, *start;
+	uint32_t                        min_len;
+	struct cdm_regcontinuous_cmd   *p_regcont_cmd;
+	struct cam_cdm_cmd_dump_header *hdr;
+
+	p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr;
+	temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
+	ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT);
+
+	min_len = (sizeof(uint32_t) * p_regcont_cmd->count) +
+		sizeof(struct cam_cdm_cmd_dump_header) +
+		(2 * sizeof(uint32_t));
+	remain_len = dump_info->dst_max_size - dump_info->dst_offset;
+
+	if (remain_len < min_len) {
+		CAM_WARN_RATE_LIMIT(CAM_CDM,
+			"Dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return ret;
+	}
+
+	dst = (char *)dump_info->dst_start + dump_info->dst_offset;
+	hdr = (struct cam_cdm_cmd_dump_header *)dst;
+	scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:");
+	hdr->word_size = sizeof(uint32_t);
+	addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
+	start = addr;
+	*addr++ = p_regcont_cmd->offset;
+	*addr++ = p_regcont_cmd->count;
+	for (i = 0; i < p_regcont_cmd->count; i++) {
+		*addr = *temp_ptr;
+		temp_ptr++;
+		addr++;
+		ret++;
+	}
+	hdr->size = hdr->word_size * (addr - start);
+	dump_info->dst_offset += hdr->size +
+		sizeof(struct cam_cdm_cmd_dump_header);
+
+	return ret;
+}
+
+static uint32_t cam_cdm_util_dump_reg_random_cmd_v2(
+	uint32_t                         *cmd_buf_addr,
+	struct cam_cdm_cmd_buf_dump_info *dump_info)
+{
+	int                             i;
+	long                            ret;
+	uint8_t                        *dst;
+	uint32_t                       *temp_ptr = cmd_buf_addr;
+	uint32_t                       *addr, *start;
+	size_t                          remain_len;
+	uint32_t                        min_len;
+	struct cdm_regrandom_cmd       *p_regrand_cmd;
+	struct cam_cdm_cmd_dump_header *hdr;
+
+	p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr;
+	temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
+	ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
+
+	min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) +
+		sizeof(struct cam_cdm_cmd_dump_header) + sizeof(uint32_t);
+	remain_len = dump_info->dst_max_size - dump_info->dst_offset;
+
+	if (remain_len < min_len) {
+		CAM_WARN_RATE_LIMIT(CAM_CDM,
+			"Dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return ret;
+	}
+
+	dst = (char *)dump_info->dst_start + dump_info->dst_offset;
+	hdr = (struct cam_cdm_cmd_dump_header *)dst;
+	scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:");
+	hdr->word_size = sizeof(uint32_t);
+	addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header));
+	start = addr;
+	*addr++ = p_regrand_cmd->count;
+	for (i = 0; i < p_regrand_cmd->count; i++) {
+		addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK;
+		addr[1] = temp_ptr[1];
+		temp_ptr += 2;
+		addr += 2;
+		ret += 2;
+	}
+	hdr->size = hdr->word_size * (addr - start);
+	dump_info->dst_offset += hdr->size +
+		sizeof(struct cam_cdm_cmd_dump_header);
+	return ret;
+}
+
+int cam_cdm_util_dump_cmd_bufs_v2(
+	struct cam_cdm_cmd_buf_dump_info *dump_info)
+{
+	uint32_t  cmd;
+	uint32_t *buf_now;
+	int rc = 0;
+
+	if (!dump_info || !dump_info->src_start || !dump_info->src_end ||
+		!dump_info->dst_start) {
+		CAM_INFO(CAM_CDM, "Invalid args");
+		return -EINVAL;
+	}
+
+	buf_now = dump_info->src_start;
+	do {
+		if (dump_info->dst_offset >= dump_info->dst_max_size) {
+			CAM_WARN(CAM_CDM,
+				"Dump overshoot offset %zu size %zu",
+				dump_info->dst_offset,
+				dump_info->dst_max_size);
+			return -ENOSPC;
+		}
+		cmd = *buf_now;
+		cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
+
+		switch (cmd) {
+		case CAM_CDM_CMD_DMI:
+		case CAM_CDM_CMD_DMI_32:
+		case CAM_CDM_CMD_DMI_64:
+			buf_now += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI);
+			break;
+		case CAM_CDM_CMD_REG_CONT:
+			buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now,
+				dump_info);
+			break;
+		case CAM_CDM_CMD_REG_RANDOM:
+			buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now,
+				dump_info);
+			break;
+		case CAM_CDM_CMD_BUFF_INDIRECT:
+			buf_now += cdm_get_cmd_header_size(
+				CAM_CDM_CMD_BUFF_INDIRECT);
+			break;
+		case CAM_CDM_CMD_GEN_IRQ:
+			buf_now += cdm_get_cmd_header_size(
+				CAM_CDM_CMD_GEN_IRQ);
+			break;
+		case CAM_CDM_CMD_WAIT_EVENT:
+			buf_now += cdm_get_cmd_header_size(
+				CAM_CDM_CMD_WAIT_EVENT);
+			break;
+		case CAM_CDM_CMD_CHANGE_BASE:
+			buf_now += cdm_get_cmd_header_size(
+				CAM_CDM_CMD_CHANGE_BASE);
+			break;
+		case CAM_CDM_CMD_PERF_CTRL:
+			buf_now += cdm_get_cmd_header_size(
+				CAM_CDM_CMD_PERF_CTRL);
+			break;
+		default:
+			CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x", cmd);
+			buf_now++;
+			break;
+		}
+	} while (buf_now <= dump_info->src_end);
+	return rc;
+}

+ 43 - 0
drivers/cam_cdm/cam_cdm_util.h

@@ -6,6 +6,9 @@
 #ifndef _CAM_CDM_UTIL_H_
 #define _CAM_CDM_UTIL_H_
 
+/* Max len for tag name for header while dumping cmd buffer*/
+#define CAM_CDM_CMD_TAG_MAX_LEN 32
+
 #include <linux/types.h>
 
 enum cam_cdm_command {
@@ -180,6 +183,34 @@ uint32_t *(*cdm_write_wait_prefetch_disable)(
 	uint32_t  mask2);
 };
 
+/**
+ * struct cam_cdm_cmd_buf_dump_info; - Camera CDM dump info
+ * @dst_offset:      dst offset
+ * @dst_max_size     max size of destination buffer
+ * @src_start:       source start address
+ * @src_end:         source end   address
+ * @dst_start:       dst start address
+ */
+struct cam_cdm_cmd_buf_dump_info {
+	size_t    dst_offset;
+	size_t    dst_max_size;
+	uint32_t *src_start;
+	uint32_t *src_end;
+	uintptr_t dst_start;
+};
+
+/**
+ * struct cam_cdm_cmd_dump_header- Camera CDM dump header
+ * @tag:       tag name for header
+ * @size:      size of data
+ * @word_size: size of each word
+ */
+struct cam_cdm_cmd_dump_header {
+	uint8_t   tag[CAM_CDM_CMD_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
 /**
  * cam_cdm_util_log_cmd_bufs()
  *
@@ -192,6 +223,18 @@ uint32_t *(*cdm_write_wait_prefetch_disable)(
 void cam_cdm_util_dump_cmd_buf(
 	uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end);
 
+/**
+ * cam_cdm_util_dump_cmd_bufs_v2()
+ *
+ * @brief:        Util function to cdm command buffers
+ *                to a buffer
+ *
+ * @dump_info:    Information about source and destination buffers
+ *
+ * return SUCCESS/FAILURE
+ */
+int cam_cdm_util_dump_cmd_bufs_v2(
+	struct cam_cdm_cmd_buf_dump_info *dump_info);
 
 
 #endif /* _CAM_CDM_UTIL_H_ */

+ 431 - 17
drivers/cam_isp/cam_isp_context.c

@@ -24,9 +24,9 @@ static const char isp_dev_name[] = "cam-isp";
 
 static struct cam_isp_ctx_debug isp_ctx_debug;
 
-#define INC_STATE_MONITOR_HEAD(head, ret) \
+#define INC_HEAD(head, max_entries, ret) \
 	div_u64_rem(atomic64_add_return(1, head),\
-	CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, (ret))
+	max_entries, (ret))
 
 static int cam_isp_context_dump_active_request(void *data, unsigned long iova,
 	uint32_t buf_info);
@@ -34,6 +34,150 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova,
 static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 	struct cam_start_stop_dev_cmd *cmd);
 
+static const char *__cam_isp_evt_val_to_type(
+	uint32_t evt_id)
+{
+	switch (evt_id) {
+	case CAM_ISP_CTX_EVENT_SUBMIT:
+		return "SUBMIT";
+	case CAM_ISP_CTX_EVENT_APPLY:
+		return "APPLY";
+	case CAM_ISP_CTX_EVENT_EPOCH:
+		return "EPOCH";
+	case CAM_ISP_CTX_EVENT_RUP:
+		return "RUP";
+	case CAM_ISP_CTX_EVENT_BUFDONE:
+		return "BUFDONE";
+	default:
+		return "CAM_ISP_EVENT_INVALID";
+	}
+}
+
+static void __cam_isp_ctx_update_event_record(
+	struct cam_isp_context *ctx_isp,
+	enum cam_isp_ctx_event  event,
+	struct cam_ctx_request *req)
+{
+	int                      iterator = 0;
+	ktime_t                  cur_time;
+	struct cam_isp_ctx_req  *req_isp;
+
+	if (!ctx_isp) {
+		CAM_ERR(CAM_ISP, "Invalid Args");
+		return;
+	}
+	switch (event) {
+	case CAM_ISP_CTX_EVENT_EPOCH:
+	case CAM_ISP_CTX_EVENT_RUP:
+	case CAM_ISP_CTX_EVENT_BUFDONE:
+		break;
+	case CAM_ISP_CTX_EVENT_SUBMIT:
+	case CAM_ISP_CTX_EVENT_APPLY:
+		if (!req) {
+			CAM_ERR(CAM_ISP, "Invalid arg for event %d", event);
+			return;
+		}
+		break;
+	default:
+		break;
+	}
+
+	INC_HEAD(&ctx_isp->event_record_head[event],
+		CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES, &iterator);
+	cur_time = ktime_get();
+	if (req) {
+		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+		ctx_isp->event_record[event][iterator].req_id =
+			req->request_id;
+		req_isp->event_timestamp[event] = cur_time;
+	} else {
+		ctx_isp->event_record[event][iterator].req_id = 0;
+	}
+	ctx_isp->event_record[event][iterator].timestamp  = cur_time;
+}
+
+static int __cam_isp_ctx_dump_event_record(
+	struct cam_isp_context *ctx_isp,
+	uintptr_t               cpu_addr,
+	size_t                  buf_len,
+	size_t                 *offset)
+{
+	int                                  i, j;
+	int                                  index;
+	size_t                               remain_len;
+	uint8_t                             *dst;
+	uint32_t                             oldest_entry, num_entries;
+	uint32_t                             min_len;
+	uint64_t                            *addr, *start;
+	uint64_t                             state_head;
+	struct timespec64                    ts;
+	struct cam_isp_context_dump_header  *hdr;
+	struct cam_isp_context_event_record *record;
+
+	if (!cpu_addr || !buf_len || !offset || !ctx_isp) {
+		CAM_ERR(CAM_ISP, "Invalid args %pK %zu %pK %pK",
+			cpu_addr, buf_len, offset, ctx_isp);
+		return -EINVAL;
+	}
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) {
+		state_head = atomic64_read(&ctx_isp->event_record_head[i]);
+
+		if (state_head == -1) {
+			return 0;
+		} else if (state_head < CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES) {
+			num_entries = state_head + 1;
+			oldest_entry = 0;
+		} else {
+			num_entries = CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES;
+			div_u64_rem(state_head + 1,
+				CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES,
+				&oldest_entry);
+		}
+		index = oldest_entry;
+
+		if (buf_len <= *offset) {
+			CAM_WARN(CAM_ISP,
+				"Dump buffer overshoot len %zu offset %zu",
+				buf_len, *offset);
+			return -ENOSPC;
+		}
+
+		min_len = sizeof(struct cam_isp_context_dump_header) +
+			((num_entries * CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS) *
+			sizeof(uint64_t));
+		remain_len = buf_len - *offset;
+
+		if (remain_len < min_len) {
+			CAM_WARN(CAM_ISP,
+				"Dump buffer exhaust remain %zu min %u",
+				remain_len, min_len);
+			return -ENOSPC;
+		}
+		dst = (uint8_t *)cpu_addr + *offset;
+		hdr = (struct cam_isp_context_dump_header *)dst;
+		scnprintf(hdr->tag,
+			CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, "ISP_EVT_%s:",
+			__cam_isp_evt_val_to_type(i));
+		hdr->word_size = sizeof(uint64_t);
+		addr = (uint64_t *)(dst +
+			sizeof(struct cam_isp_context_dump_header));
+		start = addr;
+		for (j = 0; j <  num_entries; j++) {
+			record  = &ctx_isp->event_record[i][index];
+			ts      = ktime_to_timespec64(record->timestamp);
+			*addr++ = record->req_id;
+			*addr++ = ts.tv_sec;
+			*addr++ = ts.tv_nsec/NSEC_PER_USEC;
+			index = (index + 1) %
+				CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES;
+		}
+		hdr->size = hdr->word_size * (addr - start);
+		*offset += hdr->size +
+			sizeof(struct cam_isp_context_dump_header);
+	}
+	return 0;
+}
+
 static void __cam_isp_ctx_update_state_monitor_array(
 	struct cam_isp_context *ctx_isp,
 	enum cam_isp_state_change_trigger trigger_type,
@@ -41,7 +185,8 @@ static void __cam_isp_ctx_update_state_monitor_array(
 {
 	int iterator;
 
-	INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head, &iterator);
+	INC_HEAD(&ctx_isp->state_monitor_head,
+		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &iterator);
 
 	ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state =
 		ctx_isp->substate_activated;
@@ -162,13 +307,19 @@ static int cam_isp_context_info_dump(void *context,
 	return 0;
 }
 
-static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
+static int cam_isp_ctx_dump_req(
+	struct cam_isp_ctx_req  *req_isp,
+	uintptr_t                cpu_addr,
+	size_t                   buf_len,
+	size_t                  *offset,
+	bool                     dump_to_buff)
 {
 	int i = 0, rc = 0;
 	size_t len = 0;
 	uint32_t *buf_addr;
 	uint32_t *buf_start, *buf_end;
 	size_t   remain_len = 0;
+	struct cam_cdm_cmd_buf_dump_info dump_info;
 
 	for (i = 0; i < req_isp->num_cfg; i++) {
 		rc = cam_packet_util_get_cmd_mem_addr(
@@ -182,7 +333,7 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
 				CAM_ERR(CAM_ISP,
 					"Invalid offset exp %u actual %u",
 					req_isp->cfg[i].offset, (uint32_t)len);
-				return;
+				return rc;
 			}
 			remain_len = len - req_isp->cfg[i].offset;
 
@@ -192,16 +343,33 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
 					"Invalid len exp %u remain_len %u",
 					req_isp->cfg[i].len,
 					(uint32_t)remain_len);
-				return;
+				return rc;
 			}
 
 			buf_start = (uint32_t *)((uint8_t *) buf_addr +
 				req_isp->cfg[i].offset);
 			buf_end = (uint32_t *)((uint8_t *) buf_start +
 				req_isp->cfg[i].len - 1);
-			cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+			if (dump_to_buff) {
+				if (!cpu_addr || !offset || !buf_len) {
+					CAM_ERR(CAM_ISP, "Invalid args");
+					break;
+				}
+				dump_info.src_start = buf_start;
+				dump_info.src_end =   buf_end;
+				dump_info.dst_start = cpu_addr;
+				dump_info.dst_offset = *offset;
+				dump_info.dst_max_size = buf_len;
+				rc = cam_cdm_util_dump_cmd_bufs_v2(&dump_info);
+				*offset = dump_info.dst_offset;
+				if (rc)
+					return rc;
+			} else {
+				cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+			}
 		}
 	}
+	return rc;
 }
 
 static int __cam_isp_ctx_enqueue_request_in_order(
@@ -210,6 +378,7 @@ static int __cam_isp_ctx_enqueue_request_in_order(
 	struct cam_ctx_request           *req_current;
 	struct cam_ctx_request           *req_prev;
 	struct list_head                  temp_list;
+	struct cam_isp_context           *ctx_isp;
 
 	INIT_LIST_HEAD(&temp_list);
 	spin_lock_bh(&ctx->lock);
@@ -240,6 +409,9 @@ static int __cam_isp_ctx_enqueue_request_in_order(
 			}
 		}
 	}
+	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+	__cam_isp_ctx_update_event_record(ctx_isp,
+		CAM_ISP_CTX_EVENT_SUBMIT, req);
 	spin_unlock_bh(&ctx->lock);
 	return 0;
 }
@@ -729,6 +901,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
 	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
 		CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id);
 
+	__cam_isp_ctx_update_event_record(ctx_isp,
+		CAM_ISP_CTX_EVENT_BUFDONE, req);
 	return rc;
 }
 
@@ -837,6 +1011,8 @@ static int __cam_isp_ctx_reg_upd_in_applied_state(
 		CAM_DBG(CAM_REQ,
 			"move request %lld to active list(cnt = %d), ctx %u",
 			req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
+		__cam_isp_ctx_update_event_record(ctx_isp,
+			CAM_ISP_CTX_EVENT_RUP, req);
 	} else {
 		/* no io config, so the request is completed. */
 		list_add_tail(&req->list, &ctx->free_req_list);
@@ -944,6 +1120,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
 			if (req->request_id > ctx_isp->reported_req_id) {
 				request_id = req->request_id;
 				ctx_isp->reported_req_id = request_id;
+				__cam_isp_ctx_update_event_record(ctx_isp,
+					CAM_ISP_CTX_EVENT_EPOCH, req);
 				break;
 			}
 		}
@@ -1117,7 +1295,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
 		/* Send SOF event as empty frame*/
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
-
+		__cam_isp_ctx_update_event_record(ctx_isp,
+			CAM_ISP_CTX_EVENT_EPOCH, NULL);
 		goto end;
 	}
 
@@ -1167,7 +1346,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
 	}
 	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 		CAM_REQ_MGR_SOF_EVENT_ERROR);
-
+	__cam_isp_ctx_update_event_record(ctx_isp,
+		CAM_ISP_CTX_EVENT_EPOCH, req);
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
 	CAM_DBG(CAM_ISP, "next Substate[%s]",
 		__cam_isp_ctx_substate_val_to_type(
@@ -1294,6 +1474,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
 		CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id);
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+		__cam_isp_ctx_update_event_record(ctx_isp,
+			CAM_ISP_CTX_EVENT_EPOCH, NULL);
 
 		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
 		goto end;
@@ -1345,13 +1527,21 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
 			ctx_isp->reported_req_id = request_id;
 			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_ERROR);
-		} else
+
+			__cam_isp_ctx_update_event_record(ctx_isp,
+				CAM_ISP_CTX_EVENT_EPOCH, req);
+		} else {
 			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 				CAM_REQ_MGR_SOF_EVENT_SUCCESS);
-	} else
+			__cam_isp_ctx_update_event_record(ctx_isp,
+				CAM_ISP_CTX_EVENT_EPOCH, NULL);
+		}
+	} else {
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
-
+		__cam_isp_ctx_update_event_record(ctx_isp,
+			CAM_ISP_CTX_EVENT_EPOCH, NULL);
+	}
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
 	CAM_DBG(CAM_ISP, "next Substate[%s]",
 		__cam_isp_ctx_substate_val_to_type(
@@ -1441,7 +1631,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
 	req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv;
 
 	if (error_event_data->enable_req_dump)
-		cam_isp_ctx_dump_req(req_isp);
+		rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false);
 
 	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
 		CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id);
@@ -2109,6 +2299,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
 		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
 			CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED,
 			req->request_id);
+		__cam_isp_ctx_update_event_record(ctx_isp,
+			CAM_ISP_CTX_EVENT_APPLY, req);
 	}
 end:
 	return rc;
@@ -2186,6 +2378,200 @@ static int __cam_isp_ctx_apply_req_in_bubble(
 	return rc;
 }
 
+static int __cam_isp_ctx_dump_req_info(
+	struct cam_context     *ctx,
+	struct cam_ctx_request *req,
+	uintptr_t               cpu_addr,
+	size_t                  buf_len,
+	size_t                 *offset)
+{
+	int                                 i, rc;
+	uint8_t                            *dst;
+	int32_t                            *addr, *start;
+	uint32_t                            min_len;
+	size_t                              remain_len;
+	struct cam_isp_ctx_req             *req_isp;
+	struct cam_isp_context             *ctx_isp;
+	struct cam_isp_context_dump_header *hdr;
+
+	if (!req || !ctx || !offset || !cpu_addr || !buf_len) {
+		CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %pK %zu",
+			req, ctx, offset, buf_len);
+		return -EINVAL;
+	}
+	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
+	ctx_isp = (struct cam_isp_context *)ctx->ctx_priv;
+
+	if (buf_len <= *offset) {
+		CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu",
+			buf_len, *offset);
+		return -ENOSPC;
+	}
+
+	remain_len = buf_len - *offset;
+	min_len = sizeof(struct cam_isp_context_dump_header) +
+		(CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS *
+		 req_isp->num_fence_map_out *
+		sizeof(int32_t));
+
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+
+	dst = (uint8_t *)cpu_addr + *offset;
+	hdr = (struct cam_isp_context_dump_header *)dst;
+	hdr->word_size = sizeof(int32_t);
+	scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN,
+		"ISP_OUT_FENCE:");
+	addr = (int32_t *)(dst + sizeof(struct cam_isp_context_dump_header));
+	start = addr;
+	for (i = 0; i < req_isp->num_fence_map_out; i++) {
+		*addr++ = req_isp->fence_map_out[i].resource_handle;
+		*addr++ = req_isp->fence_map_out[i].sync_id;
+	}
+	hdr->size = hdr->word_size * (addr - start);
+	*offset += hdr->size + sizeof(struct cam_isp_context_dump_header);
+	rc = cam_isp_ctx_dump_req(req_isp, cpu_addr, buf_len,
+		offset, true);
+	return rc;
+}
+
+static int __cam_isp_ctx_dump_in_top_state(
+	struct cam_context           *ctx,
+	struct cam_req_mgr_dump_info *dump_info)
+{
+	int                                 rc = 0;
+	bool                                dump_only_event_record = false;
+	size_t                              buf_len;
+	size_t                              remain_len;
+	uint8_t                            *dst;
+	ktime_t                             cur_time;
+	uint32_t                            min_len;
+	uint64_t                            diff;
+	uint64_t                           *addr, *start;
+	uintptr_t                           cpu_addr;
+	struct timespec64                   ts;
+	struct cam_isp_context             *ctx_isp;
+	struct cam_ctx_request             *req = NULL;
+	struct cam_isp_ctx_req             *req_isp;
+	struct cam_ctx_request             *req_temp;
+	struct cam_hw_dump_args             dump_args;
+	struct cam_isp_context_dump_header *hdr;
+
+	spin_lock_bh(&ctx->lock);
+	list_for_each_entry_safe(req, req_temp,
+		&ctx->active_req_list, list) {
+		if (req->request_id == dump_info->req_id) {
+			CAM_INFO(CAM_ISP, "isp dump active list req: %lld",
+			    dump_info->req_id);
+			goto hw_dump;
+		}
+	}
+	list_for_each_entry_safe(req, req_temp,
+		&ctx->wait_req_list, list) {
+		if (req->request_id == dump_info->req_id) {
+			CAM_INFO(CAM_ISP, "isp dump wait list req: %lld",
+			    dump_info->req_id);
+			goto hw_dump;
+		}
+	}
+	spin_unlock_bh(&ctx->lock);
+	return rc;
+hw_dump:
+	rc  = cam_mem_get_cpu_buf(dump_info->buf_handle,
+		&cpu_addr, &buf_len);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Invalid handle %u rc %d",
+			dump_info->buf_handle, rc);
+		spin_unlock_bh(&ctx->lock);
+		return rc;
+	}
+	if (buf_len <= dump_info->offset) {
+		spin_unlock_bh(&ctx->lock);
+		CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu",
+			buf_len, dump_info->offset);
+		return -ENOSPC;
+	}
+
+	remain_len = buf_len - dump_info->offset;
+	min_len = sizeof(struct cam_isp_context_dump_header) +
+		(CAM_ISP_CTX_DUMP_NUM_WORDS * sizeof(uint64_t));
+
+	if (remain_len < min_len) {
+		spin_unlock_bh(&ctx->lock);
+		CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+
+	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+	req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+	cur_time = ktime_get();
+	diff = ktime_us_delta(
+		req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY],
+		cur_time);
+	if (diff < CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD) {
+		CAM_INFO(CAM_ISP, "req %lld found no error",
+			req->request_id);
+		dump_only_event_record = true;
+	}
+	dst = (uint8_t *)cpu_addr + dump_info->offset;
+	hdr = (struct cam_isp_context_dump_header *)dst;
+	scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN,
+		"ISP_CTX_DUMP:");
+	hdr->word_size = sizeof(uint64_t);
+	addr = (uint64_t *)(dst +
+		sizeof(struct cam_isp_context_dump_header));
+	start = addr;
+	*addr++ = req->request_id;
+	ts      = ktime_to_timespec64(
+		req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]);
+	*addr++ = ts.tv_sec;
+	*addr++ = ts.tv_nsec/NSEC_PER_USEC;
+	ts      = ktime_to_timespec64(cur_time);
+	*addr++ = ts.tv_sec;
+	*addr++ = ts.tv_nsec/NSEC_PER_USEC;
+	hdr->size = hdr->word_size * (addr - start);
+	dump_info->offset += hdr->size +
+		sizeof(struct cam_isp_context_dump_header);
+
+	rc = __cam_isp_ctx_dump_event_record(ctx_isp, cpu_addr,
+		buf_len, &dump_info->offset);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Dump event fail %lld",
+			req->request_id);
+		spin_unlock_bh(&ctx->lock);
+		return rc;
+	}
+	if (dump_only_event_record) {
+		spin_unlock_bh(&ctx->lock);
+		return rc;
+	}
+	rc = __cam_isp_ctx_dump_req_info(ctx, req, cpu_addr,
+		buf_len, &dump_info->offset);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Dump Req info fail %lld",
+			req->request_id);
+		spin_unlock_bh(&ctx->lock);
+		return rc;
+	}
+	spin_unlock_bh(&ctx->lock);
+
+	if (ctx->hw_mgr_intf->hw_dump) {
+		dump_args.offset = dump_info->offset;
+		dump_args.request_id = dump_info->req_id;
+		dump_args.buf_handle = dump_info->buf_handle;
+		dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+		rc = ctx->hw_mgr_intf->hw_dump(
+			ctx->hw_mgr_intf->hw_mgr_priv,
+			&dump_args);
+		dump_info->offset = dump_args.offset;
+	}
+	return rc;
+}
+
 static int __cam_isp_ctx_flush_req(struct cam_context *ctx,
 	struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req)
 {
@@ -2749,7 +3135,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
 static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state(
 	struct cam_isp_context *ctx_isp, void *evt_data)
 {
-	struct cam_ctx_request  *req;
+	struct cam_ctx_request  *req = NULL;
 	struct cam_context      *ctx = ctx_isp->base;
 	struct cam_isp_ctx_req  *req_isp;
 	struct cam_req_mgr_trigger_notify  notify;
@@ -2809,12 +3195,15 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state(
 	CAM_DBG(CAM_ISP, "next Substate[%s]",
 		__cam_isp_ctx_substate_val_to_type(
 		ctx_isp->substate_activated));
-
+	__cam_isp_ctx_update_event_record(ctx_isp,
+		CAM_ISP_CTX_EVENT_RUP, req);
 	return 0;
 error:
 	/* Send SOF event as idle frame*/
 	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 		CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+	__cam_isp_ctx_update_event_record(ctx_isp,
+		CAM_ISP_CTX_EVENT_RUP, NULL);
 
 	/*
 	 * There is no request in the pending list, move the sub state machine
@@ -2974,6 +3363,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx,
 	struct cam_isp_context *ctx_isp =
 		(struct cam_isp_context *) ctx->ctx_priv;
 	struct cam_req_mgr_flush_request flush_req;
+	int i;
 
 	if (ctx_isp->hw_ctx) {
 		rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
@@ -2994,6 +3384,8 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx,
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
 	/*
 	 * Ideally, we should never have any active request here.
 	 * But we still add some sanity check code here to help the debug
@@ -3023,6 +3415,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	struct cam_release_dev_cmd *cmd)
 {
 	int rc = 0;
+	int i;
 	struct cam_hw_release_args       rel_arg;
 	struct cam_isp_context *ctx_isp =
 		(struct cam_isp_context *) ctx->ctx_priv;
@@ -3054,7 +3447,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
-
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
 	/*
 	 * Ideally, we should never have any active request here.
 	 * But we still add some sanity check code here to help the debug
@@ -3279,6 +3673,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
 	int rc = 0;
+	int i;
 	struct cam_hw_acquire_args       param;
 	struct cam_isp_resource         *isp_res = NULL;
 	struct cam_create_dev_hdl        req_hdl_param;
@@ -3391,6 +3786,8 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
 	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
 
 	kfree(isp_res);
 	isp_res = NULL;
@@ -3441,6 +3838,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
 	void *args)
 {
 	int rc = 0;
+	int i;
 	struct cam_acquire_hw_cmd_v1 *cmd =
 		(struct cam_acquire_hw_cmd_v1 *)args;
 	struct cam_hw_acquire_args       param;
@@ -3546,6 +3944,9 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
+
 	trace_cam_context_state("ISP", ctx);
 	CAM_DBG(CAM_ISP,
 		"Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u",
@@ -3855,6 +4256,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 	struct cam_start_stop_dev_cmd *cmd)
 {
 	int rc = 0;
+	int i;
 	struct cam_isp_start_args        start_isp;
 	struct cam_ctx_request          *req;
 	struct cam_isp_ctx_req          *req_isp;
@@ -3911,6 +4313,9 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
+
 	/*
 	 * In case of CSID TPG we might receive SOF and RUP IRQs
 	 * before hw_mgr_intf->hw_start has returned. So move
@@ -3941,7 +4346,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 		ctx->state = CAM_CTX_READY;
 		trace_cam_context_state("ISP", ctx);
 		if (rc == -ETIMEDOUT)
-			cam_isp_ctx_dump_req(req_isp);
+			rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false);
 		list_del_init(&req->list);
 		list_add(&req->list, &ctx->pending_req_list);
 		goto end;
@@ -4070,6 +4475,9 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
 	atomic_set(&ctx_isp->process_bubble, 0);
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx_isp->event_record_head[i], -1);
+
 	CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u",
 		ctx->state, ctx->ctx_id);
 
@@ -4326,6 +4734,7 @@ static struct cam_ctx_ops
 			.unlink = __cam_isp_ctx_unlink_in_acquired,
 			.get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
+			.dump_req = __cam_isp_ctx_dump_in_top_state,
 		},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_isp_context_dump_active_request,
@@ -4342,6 +4751,7 @@ static struct cam_ctx_ops
 		.crm_ops = {
 			.unlink = __cam_isp_ctx_unlink_in_ready,
 			.flush_req = __cam_isp_ctx_flush_req_in_ready,
+			.dump_req = __cam_isp_ctx_dump_in_top_state,
 		},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_isp_context_dump_active_request,
@@ -4376,6 +4786,7 @@ static struct cam_ctx_ops
 			.apply_req = __cam_isp_ctx_apply_req,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
 			.process_evt = __cam_isp_ctx_process_evt,
+			.dump_req = __cam_isp_ctx_dump_in_top_state,
 		},
 		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
 		.pagefault_ops = cam_isp_context_dump_active_request,
@@ -4559,6 +4970,9 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
 	}
 	atomic64_set(&ctx->state_monitor_head, -1);
 
+	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++)
+		atomic64_set(&ctx->event_record_head[i], -1);
+
 	cam_isp_context_debug_register();
 err:
 	return rc;

+ 71 - 0
drivers/cam_isp/cam_isp_context.h

@@ -33,6 +33,27 @@
  */
 #define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES   40
 
+/*
+ * Threshold response time in us beyond which a request is not expected
+ * to be with IFE hw
+ */
+#define CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD   100000
+
+/* Number of words for dumping isp context */
+#define CAM_ISP_CTX_DUMP_NUM_WORDS  5
+
+/* Number of words for dumping isp context events*/
+#define CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS  3
+
+/* Number of words for dumping request info*/
+#define CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS  2
+
+/* Maximum entries in event record */
+#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES   20
+
+/* Maximum length of tag while dumping */
+#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 32
+
 /* forward declaration */
 struct cam_isp_context;
 
@@ -55,6 +76,19 @@ enum cam_isp_ctx_activated_substate {
 	CAM_ISP_CTX_ACTIVATED_MAX,
 };
 
+/**
+ * enum cam_isp_ctx_event_type - events for a request
+ *
+ */
+enum cam_isp_ctx_event {
+	CAM_ISP_CTX_EVENT_SUBMIT,
+	CAM_ISP_CTX_EVENT_APPLY,
+	CAM_ISP_CTX_EVENT_EPOCH,
+	CAM_ISP_CTX_EVENT_RUP,
+	CAM_ISP_CTX_EVENT_BUFDONE,
+	CAM_ISP_CTX_EVENT_MAX
+};
+
 /**
  * enum cam_isp_state_change_trigger - Different types of ISP events
  *
@@ -109,6 +143,7 @@ struct cam_isp_ctx_irq_ops {
  * @bubble_report:         Flag to track if bubble report is active on
  *                         current request
  * @hw_update_data:        HW update data for this request
+ * @event_timestamp:       Timestamp for different stage of request
  * @reapply:               True if reapplying after bubble
  *
  */
@@ -125,6 +160,8 @@ struct cam_isp_ctx_req {
 	uint32_t                              num_acked;
 	int32_t                               bubble_report;
 	struct cam_isp_prepare_hw_update_data hw_update_data;
+	ktime_t                               event_timestamp
+		[CAM_ISP_CTX_EVENT_MAX];
 	bool                                  bubble_detected;
 	bool                                  reapply;
 };
@@ -160,8 +197,23 @@ struct cam_isp_context_state_monitor {
 struct cam_isp_context_req_id_info {
 	int64_t                          last_bufdone_req_id;
 };
+
 /**
  *
+ *
+ * struct cam_isp_context_event_record - Information for last 20 Events
+ *  for a request; Submit, Apply, EPOCH, RUP, Buf done.
+ *
+ * @req_id:    Last applied request id
+ * @timestamp: Timestamp for the event
+ *
+ */
+struct cam_isp_context_event_record {
+	uint64_t                         req_id;
+	ktime_t                          timestamp;
+};
+
+/**
  * struct cam_isp_context   -  ISP context object
  *
  * @base:                      Common context object pointer
@@ -187,6 +239,8 @@ struct cam_isp_context_req_id_info {
  * @state_monitor_head:        Write index to the state monitoring array
  * @req_info                   Request id information about last buf done
  * @cam_isp_ctx_state_monitor: State monitoring array
+ * @event_record_head:         Write index to the state monitoring array
+ * @event_record:              Event record array
  * @rdi_only_context:          Get context type information.
  *                             true, if context is rdi only context
  * @hw_acquired:               Indicate whether HW resources are acquired
@@ -221,6 +275,10 @@ struct cam_isp_context {
 	struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[
 		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES];
 	struct cam_isp_context_req_id_info    req_info;
+	atomic64_t                            event_record_head[
+		CAM_ISP_CTX_EVENT_MAX];
+	struct cam_isp_context_event_record   event_record[
+		CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES];
 	bool                                  rdi_only_context;
 	bool                                  hw_acquired;
 	bool                                  init_received;
@@ -229,6 +287,19 @@ struct cam_isp_context {
 	uint32_t                              isp_device_type;
 };
 
+/**
+ * struct cam_isp_context_dump_header - ISP context dump header
+ * @tag:       Tag name for the header
+ * @word_size: Size of word
+ * @size:      Size of data
+ *
+ */
+struct cam_isp_context_dump_header {
+	uint8_t   tag[CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
 /**
  * cam_isp_context_init()
  *

+ 160 - 5
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -134,7 +134,9 @@ static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type,
 
 static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx,
 	struct cam_cmd_buf_desc *reg_dump_buf_desc, uint32_t num_reg_dump_buf,
-	uint32_t meta_type)
+	uint32_t meta_type,
+	void *soc_dump_args,
+	bool user_triggered_dump)
 {
 	int rc = 0, i;
 
@@ -157,7 +159,9 @@ static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx,
 			rc = cam_soc_util_reg_dump_to_cmd_buf(ctx,
 				&reg_dump_buf_desc[i],
 				ctx->applied_req_id,
-				cam_ife_mgr_regspace_data_cb);
+				cam_ife_mgr_regspace_data_cb,
+				soc_dump_args,
+				user_triggered_dump);
 			if (rc) {
 				CAM_ERR(CAM_ISP,
 					"Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u",
@@ -2427,7 +2431,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata,
 			cam_ife_mgr_handle_reg_dump(ctx,
 				hw_update_data->reg_dump_buf_desc,
 				hw_update_data->num_reg_dump_buf,
-				CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST);
+				CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST,
+				NULL, false);
 
 		CAM_DBG(CAM_ISP,
 			"Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d",
@@ -5943,7 +5948,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 		ctx->last_dump_flush_req_id = ctx->applied_req_id;
 		rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc,
 			ctx->num_reg_dump_buf,
-			CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH);
+			CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH, NULL, false);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Reg dump on flush failed req id: %llu rc: %d",
@@ -5959,7 +5964,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 		ctx->last_dump_err_req_id = ctx->applied_req_id;
 		rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc,
 			ctx->num_reg_dump_buf,
-			CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR);
+			CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, NULL, false);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Reg dump on error failed req id: %llu rc: %d",
@@ -5978,6 +5983,155 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 	return rc;
 }
 
+static int cam_ife_mgr_user_dump_hw(
+		struct cam_ife_hw_mgr_ctx *ife_ctx,
+		struct cam_hw_dump_args *dump_args)
+{
+	int rc = 0;
+	struct cam_hw_soc_dump_args soc_dump_args;
+
+	if (!ife_ctx || !dump_args) {
+		CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK",
+			ife_ctx, dump_args);
+		rc = -EINVAL;
+		goto end;
+	}
+	soc_dump_args.buf_handle = dump_args->buf_handle;
+	soc_dump_args.request_id = dump_args->request_id;
+	soc_dump_args.offset = dump_args->offset;
+
+	rc = cam_ife_mgr_handle_reg_dump(ife_ctx,
+		ife_ctx->reg_dump_buf_desc,
+		ife_ctx->num_reg_dump_buf,
+		CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR,
+		&soc_dump_args,
+		true);
+	if (rc) {
+		CAM_ERR(CAM_ISP,
+			"Dump failed req: %lld handle %u offset %u",
+			dump_args->request_id,
+			dump_args->buf_handle,
+			dump_args->offset);
+		goto end;
+	}
+	dump_args->offset = soc_dump_args.offset;
+end:
+	return rc;
+}
+
+static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args)
+{
+	struct cam_isp_hw_dump_args isp_hw_dump_args;
+	struct cam_hw_dump_args *dump_args = (struct cam_hw_dump_args *)args;
+	struct cam_isp_hw_mgr_res            *hw_mgr_res;
+	struct cam_hw_intf                   *hw_intf;
+	struct cam_ife_hw_mgr_ctx *ife_ctx = (struct cam_ife_hw_mgr_ctx *)
+						dump_args->ctxt_to_hw_map;
+	int i;
+	int rc = 0;
+
+	/* for some targets, information about the IFE registers to be dumped
+	 * is already submitted with the hw manager. In this case, we
+	 * can dump just the related registers and skip going to core files.
+	 */
+	if (ife_ctx->num_reg_dump_buf) {
+		cam_ife_mgr_user_dump_hw(ife_ctx, dump_args);
+		goto end;
+	}
+
+	rc  = cam_mem_get_cpu_buf(dump_args->buf_handle,
+		&isp_hw_dump_args.cpu_addr,
+		&isp_hw_dump_args.buf_len);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Invalid handle %u rc %d",
+			dump_args->buf_handle, rc);
+		return rc;
+	}
+
+	isp_hw_dump_args.offset = dump_args->offset;
+	isp_hw_dump_args.req_id = dump_args->request_id;
+
+	list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			switch (hw_mgr_res->hw_res[i]->res_id) {
+			case CAM_IFE_PIX_PATH_RES_RDI_0:
+			case CAM_IFE_PIX_PATH_RES_RDI_1:
+			case CAM_IFE_PIX_PATH_RES_RDI_2:
+			case CAM_IFE_PIX_PATH_RES_RDI_3:
+				if (ife_ctx->is_rdi_only_context &&
+					hw_intf->hw_ops.process_cmd) {
+					rc = hw_intf->hw_ops.process_cmd(
+						hw_intf->hw_priv,
+						CAM_ISP_HW_CMD_DUMP_HW,
+						&isp_hw_dump_args,
+						sizeof(struct
+						    cam_isp_hw_dump_args));
+				}
+				break;
+			case CAM_IFE_PIX_PATH_RES_IPP:
+				if (hw_intf->hw_ops.process_cmd) {
+					rc = hw_intf->hw_ops.process_cmd(
+						hw_intf->hw_priv,
+						CAM_ISP_HW_CMD_DUMP_HW,
+						&isp_hw_dump_args,
+						sizeof(struct
+						    cam_isp_hw_dump_args));
+				}
+				break;
+			default:
+				CAM_DBG(CAM_ISP, "not a valid res %d",
+				hw_mgr_res->res_id);
+				break;
+			}
+		}
+	}
+
+	list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			switch (hw_mgr_res->res_id) {
+			case CAM_ISP_HW_VFE_IN_RDI0:
+			case CAM_ISP_HW_VFE_IN_RDI1:
+			case CAM_ISP_HW_VFE_IN_RDI2:
+			case CAM_ISP_HW_VFE_IN_RDI3:
+				if (ife_ctx->is_rdi_only_context &&
+					hw_intf->hw_ops.process_cmd) {
+					rc = hw_intf->hw_ops.process_cmd(
+						hw_intf->hw_priv,
+						CAM_ISP_HW_CMD_DUMP_HW,
+						&isp_hw_dump_args,
+						sizeof(struct
+						    cam_isp_hw_dump_args));
+				}
+				break;
+			case CAM_ISP_HW_VFE_IN_CAMIF:
+				if (hw_intf->hw_ops.process_cmd) {
+					rc = hw_intf->hw_ops.process_cmd(
+						hw_intf->hw_priv,
+						CAM_ISP_HW_CMD_DUMP_HW,
+						&isp_hw_dump_args,
+						sizeof(struct
+						    cam_isp_hw_dump_args));
+				}
+				break;
+			default:
+				CAM_DBG(CAM_ISP, "not a valid res %d",
+					hw_mgr_res->res_id);
+				break;
+			}
+		}
+	}
+	dump_args->offset = isp_hw_dump_args.offset;
+end:
+	CAM_DBG(CAM_ISP, "offset %u", dump_args->offset);
+	return rc;
+}
+
 static int cam_ife_mgr_cmd_get_sof_timestamp(
 	struct cam_ife_hw_mgr_ctx            *ife_ctx,
 	uint64_t                             *time_stamp,
@@ -6957,6 +7111,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
 	hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
 	hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd;
 	hw_mgr_intf->hw_reset = cam_ife_mgr_reset;
+	hw_mgr_intf->hw_dump = cam_ife_mgr_dump;
 
 	if (iommu_hdl)
 		*iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl;

+ 3 - 1
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -140,7 +140,9 @@ static int cam_tfe_mgr_handle_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx,
 			rc = cam_soc_util_reg_dump_to_cmd_buf(ctx,
 				&reg_dump_buf_desc[i],
 				ctx->applied_req_id,
-				cam_tfe_mgr_regspace_data_cb);
+				cam_tfe_mgr_regspace_data_cb,
+				NULL,
+				false);
 			if (rc) {
 				CAM_ERR(CAM_ISP,
 					"Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u",

+ 66 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c

@@ -3808,7 +3808,70 @@ static int cam_ife_csid_set_epd_config(
 
 	csid_hw->epd_supported = epd_update->epd_supported;
 	CAM_DBG(CAM_ISP, "CSID EPD supported %d", csid_hw->epd_supported);
+	return 0;
+}
 
+static int cam_ife_csid_dump_hw(
+	struct cam_ife_csid_hw *csid_hw, void *cmd_args)
+{
+	int                             i;
+	uint8_t                        *dst;
+	uint32_t                       *addr, *start;
+	uint32_t                        min_len;
+	uint32_t                        num_reg;
+	size_t                          remain_len;
+	struct cam_isp_hw_dump_header  *hdr;
+	struct cam_isp_hw_dump_args    *dump_args =
+		(struct cam_isp_hw_dump_args *)cmd_args;
+	struct cam_hw_soc_info         *soc_info;
+
+	if (!dump_args) {
+		CAM_ERR(CAM_ISP, "Invalid args");
+		return -EINVAL;
+	}
+	if (!dump_args->cpu_addr || !dump_args->buf_len) {
+		CAM_ERR(CAM_ISP,
+			"Invalid params %pK %zu",
+			(void *)dump_args->cpu_addr,
+			dump_args->buf_len);
+		return -EINVAL;
+	}
+	soc_info = &csid_hw->hw_info->soc_info;
+	if (dump_args->buf_len <= dump_args->offset) {
+		CAM_WARN(CAM_ISP,
+			"Dump offset overshoot offset %zu buf_len %zu",
+			dump_args->offset, dump_args->buf_len);
+		return -ENOSPC;
+	}
+	min_len = soc_info->reg_map[0].size +
+		sizeof(struct cam_isp_hw_dump_header) +
+		sizeof(uint32_t);
+	remain_len = dump_args->buf_len - dump_args->offset;
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+	dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
+	hdr = (struct cam_isp_hw_dump_header *)dst;
+	scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "CSID_REG:");
+	addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header));
+
+	start = addr;
+	num_reg = soc_info->reg_map[0].size/4;
+	hdr->word_size = sizeof(uint32_t);
+	*addr = soc_info->index;
+	addr++;
+	for (i = 0; i < num_reg; i++) {
+		addr[0] = soc_info->mem_block[0]->start + (i*4);
+		addr[1] = cam_io_r(soc_info->reg_map[0].mem_base
+			+ (i*4));
+		addr += 2;
+	}
+	hdr->size = hdr->word_size * (addr - start);
+	dump_args->offset +=  hdr->size +
+		sizeof(struct cam_isp_hw_dump_header);
+	CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset);
 	return 0;
 }
 
@@ -3852,6 +3915,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
 	case CAM_IFE_CSID_SET_CONFIG:
 		rc = cam_ife_csid_set_epd_config(csid_hw, cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_DUMP_HW:
+		rc = cam_ife_csid_dump_hw(csid_hw, cmd_args);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 39 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -13,6 +13,8 @@
 #include "cam_irq_controller.h"
 #include "cam_hw_intf.h"
 
+/* Maximum length of tag while dumping */
+#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 32
 /*
  * struct cam_isp_timestamp:
  *
@@ -111,6 +113,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA,
 	CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE,
 	CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP,
+	CAM_ISP_HW_CMD_DUMP_HW,
 	CAM_ISP_HW_CMD_MAX,
 };
 
@@ -253,4 +256,40 @@ struct cam_isp_hw_dual_isp_update_args {
 	struct cam_isp_resource_node    *res;
 	struct cam_isp_dual_config      *dual_cfg;
 };
+
+/*
+ * struct cam_isp_hw_dump_args:
+ *
+ * @Brief:        isp hw dump args
+ *
+ * @ req_id:         request id
+ * @ cpu_addr:       cpu address
+ * @ buf_len:        buf len
+ * @ offset:         offset of buffer
+ * @ ctxt_to_hw_map: ctx to hw map
+ */
+struct cam_isp_hw_dump_args {
+	uint64_t                req_id;
+	uintptr_t               cpu_addr;
+	size_t                  buf_len;
+	size_t                  offset;
+	void                   *ctxt_to_hw_map;
+};
+
+/**
+ * struct cam_isp_hw_dump_header - ISP context dump header
+ *
+ * @Brief:        isp hw dump header
+ *
+ * @tag:       Tag name for the header
+ * @word_size: Size of word
+ * @size:      Size of data
+ *
+ */
+struct cam_isp_hw_dump_header {
+	uint8_t   tag[CAM_ISP_HW_DUMP_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
 #endif /* _CAM_ISP_HW_H_ */

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c

@@ -595,6 +595,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_BW_CONTROL:
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 	case CAM_ISP_HW_CMD_BW_UPDATE_V2:
+	case CAM_ISP_HW_CMD_DUMP_HW:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);

+ 28 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE170_H_
@@ -144,6 +144,32 @@ static struct cam_vfe_rdi_reg_data  vfe_170_rdi_2_data = {
 	.reg_update_irq_mask      = 0x80,
 };
 
+struct cam_vfe_top_dump_data vfe170_dump_data = {
+	.num_reg_dump_entries  =  2,
+	.num_lut_dump_entries  =  1,
+	.dmi_cfg               =  0xc24,
+	.dmi_addr              =  0xc28,
+	.dmi_data_path_hi      =  0xc2C,
+	.dmi_data_path_lo      =  0xc30,
+	.reg_entry = {
+		{
+			.reg_dump_start = 0x0,
+			.reg_dump_end   = 0x1164,
+		},
+		{
+			.reg_dump_start = 0x2000,
+			.reg_dump_end   = 0x397C,
+		},
+	},
+	.lut_entry = {
+		{
+			.lut_word_size = 64,
+			.lut_bank_sel  = 0x40,
+			.lut_addr_size = 180,
+		},
+	},
+};
+
 static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = {
 	.common_reg = &vfe170_top_common_reg,
 	.camif_hw_info = {
@@ -173,6 +199,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = {
 		CAM_VFE_RDI_VER_1_0,
 		CAM_VFE_RDI_VER_1_0,
 	},
+	.dump_data = &vfe170_dump_data,
 };
 
 static struct cam_irq_register_set vfe170_bus_irq_reg[3] = {

+ 28 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE175_H_
@@ -178,6 +178,32 @@ static struct cam_vfe_rdi_reg_data  vfe_175_rdi_2_data = {
 	.reg_update_irq_mask      = 0x80,
 };
 
+struct cam_vfe_top_dump_data vfe175_dump_data = {
+	.num_reg_dump_entries  =  2,
+	.num_lut_dump_entries  =  1,
+	.dmi_cfg               =  0xc24,
+	.dmi_addr              =  0xc28,
+	.dmi_data_path_hi      =  0xc2C,
+	.dmi_data_path_lo      =  0xc30,
+	.reg_entry = {
+		{
+			.reg_dump_start = 0x0,
+			.reg_dump_end   = 0x1164,
+		},
+		{
+			.reg_dump_start = 0x2000,
+			.reg_dump_end   = 0x397C,
+		},
+	},
+	.lut_entry = {
+		{
+			.lut_word_size = 64,
+			.lut_bank_sel  = 0x40,
+			.lut_addr_size = 180,
+		},
+	},
+};
+
 static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = {
 	.common_reg = &vfe175_top_common_reg,
 	.camif_hw_info = {
@@ -209,6 +235,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = {
 		CAM_VFE_RDI_VER_1_0,
 		CAM_VFE_CAMIF_LITE_VER_2_0,
 	},
+	.dump_data = &vfe175_dump_data,
 };
 
 static struct cam_irq_register_set vfe175_bus_irq_reg[3] = {

+ 28 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE175_130_H_
@@ -226,6 +226,32 @@ static struct cam_vfe_rdi_reg_data  vfe_175_130_rdi_2_data = {
 	.reg_update_irq_mask      = 0x80,
 };
 
+struct cam_vfe_top_dump_data vfe175_130_dump_data = {
+	.num_reg_dump_entries  =  2,
+	.num_lut_dump_entries  =  1,
+	.dmi_cfg               =  0xc24,
+	.dmi_addr              =  0xc28,
+	.dmi_data_path_hi      =  0xc2C,
+	.dmi_data_path_lo      =  0xc30,
+	.reg_entry = {
+		{
+			.reg_dump_start = 0x0,
+			.reg_dump_end   = 0x1164,
+		},
+		{
+			.reg_dump_start = 0x2000,
+			.reg_dump_end   = 0x397C,
+		},
+	},
+	.lut_entry = {
+		{
+			.lut_word_size = 64,
+			.lut_bank_sel  = 0x40,
+			.lut_addr_size = 180,
+		},
+	},
+};
+
 static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = {
 	.common_reg = &vfe175_130_top_common_reg,
 	.camif_hw_info = {
@@ -263,6 +289,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = {
 		CAM_VFE_CAMIF_LITE_VER_2_0,
 		CAM_VFE_IN_RD_VER_1_0,
 	},
+	.dump_data = &vfe175_130_dump_data,
 };
 
 static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = {

+ 29 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE_TOP_COMMON_H_
@@ -13,6 +13,10 @@
 #include "cam_vfe_hw_intf.h"
 #include "cam_vfe_soc.h"
 
+#define CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES 70
+
+#define CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES 6
+
 struct cam_vfe_top_priv_common {
 	struct cam_isp_resource_node    mux_rsrc[CAM_VFE_TOP_MUX_MAX];
 	uint32_t                        num_mux;
@@ -26,6 +30,30 @@ struct cam_vfe_top_priv_common {
 	enum cam_vfe_bw_control_action  axi_vote_control[CAM_VFE_TOP_MUX_MAX];
 };
 
+struct cam_vfe_top_reg_dump_entry {
+	uint32_t reg_dump_start;
+	uint32_t reg_dump_end;
+};
+
+struct cam_vfe_top_lut_dump_entry {
+	uint32_t lut_word_size;
+	uint32_t lut_bank_sel;
+	uint32_t lut_addr_size;
+};
+
+struct cam_vfe_top_dump_data {
+	uint32_t num_reg_dump_entries;
+	uint32_t num_lut_dump_entries;
+	uint32_t dmi_cfg;
+	uint32_t dmi_addr;
+	uint32_t dmi_data_path_hi;
+	uint32_t dmi_data_path_lo;
+	struct cam_vfe_top_reg_dump_entry
+		reg_entry[CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES];
+	struct cam_vfe_top_lut_dump_entry
+		lut_entry[CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES];
+};
+
 int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
 	struct cam_vfe_top_priv_common *top_common, bool start_stop);
 

+ 141 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -19,6 +19,7 @@ struct cam_vfe_top_ver2_common_data {
 	struct cam_hw_soc_info                     *soc_info;
 	struct cam_hw_intf                         *hw_intf;
 	struct cam_vfe_top_ver2_reg_offset_common  *common_reg;
+	struct cam_vfe_top_dump_data               *dump_data;
 };
 
 struct cam_vfe_top_ver2_priv {
@@ -184,6 +185,140 @@ int cam_vfe_top_get_hw_caps(void *device_priv,
 	return -EPERM;
 }
 
+static int cam_vfe_hw_dump(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args,
+	uint32_t arg_size)
+{
+	int                                i, j;
+	uint8_t                           *dst;
+	uint32_t                           reg_start_offset;
+	uint32_t                           reg_dump_size = 0;
+	uint32_t                           lut_dump_size = 0;
+	uint32_t                           val;
+	uint32_t                           num_reg;
+	void __iomem                      *reg_base;
+	uint32_t                          *addr, *start;
+	size_t                             remain_len;
+	uint32_t                           min_len;
+	struct cam_hw_soc_info            *soc_info;
+	struct cam_vfe_top_dump_data      *dump_data;
+	struct cam_isp_hw_dump_header     *hdr;
+	struct cam_isp_hw_dump_args       *dump_args =
+		(struct cam_isp_hw_dump_args *)cmd_args;
+
+	if (!dump_args) {
+		CAM_ERR(CAM_ISP, "Invalid args");
+		return -EINVAL;
+	}
+	if (!dump_args->cpu_addr || !dump_args->buf_len) {
+		CAM_ERR(CAM_ISP,
+			"Invalid params %pK %zu",
+			(void *)dump_args->cpu_addr,
+			dump_args->buf_len);
+		return -EINVAL;
+	}
+	if (dump_args->buf_len <= dump_args->offset) {
+		CAM_WARN(CAM_ISP,
+			"Dump offset overshoot offset %zu buf_len %zu",
+			dump_args->offset, dump_args->buf_len);
+		return -ENOSPC;
+	}
+	dump_data = top_priv->common_data.dump_data;
+	soc_info = top_priv->common_data.soc_info;
+
+	/*Dump registers */
+	for (i = 0; i < dump_data->num_reg_dump_entries; i++)
+		reg_dump_size += (dump_data->reg_entry[i].reg_dump_end -
+			dump_data->reg_entry[i].reg_dump_start);
+	/*
+	 * We dump the offset as well, so the total size dumped becomes
+	 * multiplied by 2
+	 */
+	reg_dump_size *= 2;
+	for (i = 0; i < dump_data->num_lut_dump_entries; i++)
+		lut_dump_size += ((dump_data->lut_entry[i].lut_addr_size) *
+			(dump_data->lut_entry[i].lut_word_size/8));
+
+	/*Minimum len comprises of:
+	 * soc_index
+	 * lut_dump_size + reg_dump_size + sizeof dump_header +
+	 * (num_lut_dump_entries--> represents number of banks)
+	 */
+	min_len = sizeof(uint32_t) + lut_dump_size + reg_dump_size +
+		sizeof(struct cam_isp_hw_dump_header) +
+		(dump_data->num_lut_dump_entries * sizeof(uint32_t));
+	remain_len = dump_args->buf_len - dump_args->offset;
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+
+	dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
+	hdr = (struct cam_isp_hw_dump_header *)dst;
+	hdr->word_size = sizeof(uint32_t);
+	scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "VFE_REG:");
+	addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header));
+	start = addr;
+	*addr++ = soc_info->index;
+	for (i = 0; i < dump_data->num_reg_dump_entries; i++) {
+		num_reg  = (dump_data->reg_entry[i].reg_dump_end -
+			dump_data->reg_entry[i].reg_dump_start)/4;
+		reg_start_offset = dump_data->reg_entry[i].reg_dump_start;
+		reg_base = soc_info->reg_map[0].mem_base + reg_start_offset;
+		for (j = 0; j < num_reg; j++) {
+			addr[0] = soc_info->mem_block[0]->start +
+				reg_start_offset + (j*4);
+			addr[1] = cam_io_r(reg_base + (j*4));
+			addr += 2;
+		}
+	}
+	hdr->size = hdr->word_size * (addr - start);
+	dump_args->offset +=  hdr->size +
+		sizeof(struct cam_isp_hw_dump_header);
+
+	/*dump LUT*/
+	for (i = 0; i < dump_data->num_lut_dump_entries; i++) {
+
+		dst = (char *)dump_args->cpu_addr + dump_args->offset;
+		hdr = (struct cam_isp_hw_dump_header *)dst;
+		scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "LUT_REG:");
+		hdr->word_size = dump_data->lut_entry[i].lut_word_size/8;
+		addr = (uint32_t *)(dst +
+			sizeof(struct cam_isp_hw_dump_header));
+		start = addr;
+		*addr++ = dump_data->lut_entry[i].lut_bank_sel;
+		val = 0x100 |  dump_data->lut_entry[i].lut_bank_sel;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			dump_data->dmi_cfg);
+		cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+			dump_data->dmi_addr);
+		for (j = 0; j < dump_data->lut_entry[i].lut_addr_size;
+			j++) {
+			if (dump_data->lut_entry[i].lut_word_size == 64) {
+				addr[0] = cam_io_r(
+					soc_info->reg_map[0].mem_base +
+					dump_data->dmi_data_path_lo);
+				addr[1] = cam_io_r(
+					soc_info->reg_map[0].mem_base +
+					dump_data->dmi_data_path_hi);
+				addr += 2;
+			} else {
+				*addr = cam_io_r(
+					soc_info->reg_map[0].mem_base +
+					dump_data->dmi_data_path_lo);
+				addr++;
+			}
+		}
+		hdr->size = hdr->word_size * (addr - start);
+		dump_args->offset +=  hdr->size +
+			sizeof(struct cam_isp_hw_dump_header);
+	}
+	CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset);
+	return 0;
+}
+
 int cam_vfe_top_init_hw(void *device_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
@@ -505,6 +640,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common,
 			cmd_args, arg_size);
 		break;
+	case CAM_ISP_HW_CMD_DUMP_HW:
+		rc = cam_vfe_hw_dump(top_priv,
+			cmd_args, arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -627,6 +766,7 @@ int cam_vfe_top_ver2_init(
 	top_priv->common_data.hw_intf      = hw_intf;
 	top_priv->top_common.hw_idx        = hw_intf->hw_idx;
 	top_priv->common_data.common_reg   = ver2_hw_info->common_reg;
+	top_priv->common_data.dump_data    = ver2_hw_info->dump_data;
 
 	return rc;
 

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE_TOP_VER2_H_
@@ -49,6 +49,7 @@ struct cam_vfe_top_ver2_hw_info {
 	struct cam_vfe_camif_lite_ver2_hw_info      camif_lite_hw_info;
 	struct cam_vfe_rdi_ver2_hw_info             rdi_hw_info;
 	struct cam_vfe_fe_ver1_hw_info              fe_hw_info;
+	struct cam_vfe_top_dump_data               *dump_data;
 	uint32_t                                    num_mux;
 	uint32_t mux_type[CAM_VFE_TOP_MUX_MAX];
 };

+ 285 - 7
drivers/cam_utils/cam_soc_util.c

@@ -2002,9 +2002,268 @@ end:
 	return rc;
 }
 
+static int cam_soc_util_dump_dmi_reg_range_user_buf(
+	struct cam_hw_soc_info *soc_info,
+	struct cam_dmi_read_desc *dmi_read, uint32_t base_idx,
+	struct cam_hw_soc_dump_args *dump_args)
+{
+	int                            i;
+	int                            rc;
+	size_t                         buf_len = 0;
+	uint8_t                       *dst;
+	size_t                         remain_len;
+	uint32_t                       min_len;
+	uint32_t                      *waddr, *start;
+	uintptr_t                      cpu_addr;
+	struct cam_hw_soc_dump_header *hdr;
+
+	if (!soc_info || !dump_args || !dmi_read) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid input args soc_info: %pK, dump_args: %pK",
+			soc_info, dump_args);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX ||
+		dmi_read->num_post_writes > CAM_REG_DUMP_DMI_CONFIG_MAX) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid number of requested writes, pre: %d post: %d",
+			dmi_read->num_pre_writes, dmi_read->num_post_writes);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len);
+	if (rc) {
+		CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d",
+			dump_args->buf_handle, rc);
+		goto end;
+	}
+
+	if (buf_len <= dump_args->offset) {
+		CAM_WARN(CAM_UTIL, "Dump offset overshoot offset %zu len %zu",
+			dump_args->offset, buf_len);
+		rc = -ENOSPC;
+		goto end;
+	}
+	remain_len = buf_len - dump_args->offset;
+	min_len = (dmi_read->num_pre_writes * 2 * sizeof(uint32_t)) +
+		(dmi_read->dmi_data_read.num_values * 2 * sizeof(uint32_t)) +
+		sizeof(uint32_t);
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_UTIL,
+			"Dump Buffer exhaust read %d write %d remain %zu min %u",
+			dmi_read->dmi_data_read.num_values,
+			dmi_read->num_pre_writes, remain_len,
+			min_len);
+		rc = -ENOSPC;
+		goto end;
+	}
+
+	dst = (uint8_t *)cpu_addr + dump_args->offset;
+	hdr = (struct cam_hw_soc_dump_header *)dst;
+	memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header));
+	scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN,
+		"DMI_DUMP:");
+	waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header));
+	start = waddr;
+	hdr->word_size = sizeof(uint32_t);
+	*waddr = soc_info->index;
+	waddr++;
+	for (i = 0; i < dmi_read->num_pre_writes; i++) {
+		if (dmi_read->pre_read_config[i].offset >
+			(uint32_t)soc_info->reg_map[base_idx].size) {
+			CAM_ERR(CAM_UTIL,
+				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
+				dmi_read->pre_read_config[i].offset,
+				(uint32_t)soc_info->reg_map[base_idx].size);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		cam_soc_util_w_mb(soc_info, base_idx,
+			dmi_read->pre_read_config[i].offset,
+			dmi_read->pre_read_config[i].value);
+		*waddr++ = dmi_read->pre_read_config[i].offset;
+		*waddr++ = dmi_read->pre_read_config[i].value;
+	}
+
+	if (dmi_read->dmi_data_read.offset >
+		(uint32_t)soc_info->reg_map[base_idx].size) {
+		CAM_ERR(CAM_UTIL,
+			"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
+			dmi_read->dmi_data_read.offset,
+			(uint32_t)soc_info->reg_map[base_idx].size);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) {
+		*waddr++ = dmi_read->dmi_data_read.offset;
+		*waddr++ = cam_soc_util_r_mb(soc_info, base_idx,
+			dmi_read->dmi_data_read.offset);
+	}
+
+	for (i = 0; i < dmi_read->num_post_writes; i++) {
+		if (dmi_read->post_read_config[i].offset >
+			(uint32_t)soc_info->reg_map[base_idx].size) {
+			CAM_ERR(CAM_UTIL,
+				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
+				dmi_read->post_read_config[i].offset,
+				(uint32_t)soc_info->reg_map[base_idx].size);
+			rc = -EINVAL;
+			goto end;
+		}
+		cam_soc_util_w_mb(soc_info, base_idx,
+			dmi_read->post_read_config[i].offset,
+			dmi_read->post_read_config[i].value);
+	}
+	hdr->size = (waddr - start) * hdr->word_size;
+	dump_args->offset +=  hdr->size +
+		sizeof(struct cam_hw_soc_dump_header);
+
+end:
+	return rc;
+}
+
+static int cam_soc_util_dump_cont_reg_range_user_buf(
+	struct cam_hw_soc_info *soc_info,
+	struct cam_reg_range_read_desc *reg_read,
+	uint32_t base_idx,
+	struct cam_hw_soc_dump_args *dump_args)
+{
+	int                            i;
+	int                            rc = 0;
+	size_t                         buf_len;
+	uint8_t                       *dst;
+	size_t                         remain_len;
+	uint32_t                       min_len;
+	uint32_t                      *waddr, *start;
+	uintptr_t                      cpu_addr;
+	struct cam_hw_soc_dump_header  *hdr;
+
+	if (!soc_info || !dump_args || !reg_read) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid input args soc_info: %pK, dump_out_buffer: %pK reg_read: %pK",
+			soc_info, dump_args, reg_read);
+		rc = -EINVAL;
+		goto end;
+	}
+	rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len);
+	if (rc) {
+		CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d",
+			dump_args->buf_handle, rc);
+		goto end;
+	}
+	if (buf_len <= dump_args->offset) {
+		CAM_WARN(CAM_UTIL, "Dump offset overshoot %zu %zu",
+			dump_args->offset, buf_len);
+		rc = -ENOSPC;
+		goto end;
+	}
+	remain_len = buf_len - dump_args->offset;
+	min_len = (reg_read->num_values * 2 * sizeof(uint32_t)) +
+		sizeof(struct cam_hw_soc_dump_header) + sizeof(uint32_t);
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_UTIL,
+			"Dump Buffer exhaust read_values %d remain %zu min %u",
+			reg_read->num_values,
+			remain_len,
+			min_len);
+		rc = -ENOSPC;
+		goto end;
+	}
+	dst = (uint8_t *)cpu_addr + dump_args->offset;
+	hdr = (struct cam_hw_soc_dump_header *)dst;
+	memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header));
+	scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN, "%s_REG:",
+		soc_info->dev_name);
+	waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header));
+	start = waddr;
+	hdr->word_size = sizeof(uint32_t);
+	*waddr = soc_info->index;
+	waddr++;
+	for (i = 0; i < reg_read->num_values; i++) {
+		if ((reg_read->offset + (i * sizeof(uint32_t))) >
+			(uint32_t)soc_info->reg_map[base_idx].size) {
+			CAM_ERR(CAM_UTIL,
+				"Reg offset out of range, offset: 0x%X reg_map size: 0x%X",
+				(reg_read->offset + (i * sizeof(uint32_t))),
+				(uint32_t)soc_info->reg_map[base_idx].size);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		waddr[0] = reg_read->offset + (i * sizeof(uint32_t));
+		waddr[1] = cam_soc_util_r(soc_info, base_idx,
+			(reg_read->offset + (i * sizeof(uint32_t))));
+		waddr += 2;
+	}
+	hdr->size = (waddr - start) * hdr->word_size;
+	dump_args->offset +=  hdr->size +
+		sizeof(struct cam_hw_soc_dump_header);
+end:
+	return rc;
+}
+
+static int cam_soc_util_user_reg_dump(
+	struct cam_reg_dump_desc *reg_dump_desc,
+	struct cam_hw_soc_dump_args *dump_args,
+	struct cam_hw_soc_info *soc_info,
+	uint32_t reg_base_idx)
+{
+	int rc = 0;
+	int i;
+	struct cam_reg_read_info  *reg_read_info = NULL;
+
+	if (!dump_args || !reg_dump_desc || !soc_info) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid input parameters %pK %pK %pK",
+			dump_args, reg_dump_desc, soc_info);
+		return -EINVAL;
+	}
+	for (i = 0; i < reg_dump_desc->num_read_range; i++) {
+
+		reg_read_info = &reg_dump_desc->read_range[i];
+		if (reg_read_info->type ==
+				CAM_REG_DUMP_READ_TYPE_CONT_RANGE) {
+			rc = cam_soc_util_dump_cont_reg_range_user_buf(
+				soc_info,
+				&reg_read_info->reg_read,
+				reg_base_idx,
+				dump_args);
+		} else if (reg_read_info->type ==
+				CAM_REG_DUMP_READ_TYPE_DMI) {
+			rc = cam_soc_util_dump_dmi_reg_range_user_buf(
+				soc_info,
+				&reg_read_info->dmi_read,
+				reg_base_idx,
+				dump_args);
+		} else {
+			CAM_ERR(CAM_UTIL,
+					"Invalid Reg dump read type: %d",
+					reg_read_info->type);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		if (rc) {
+			CAM_ERR(CAM_UTIL,
+				"Reg range read failed rc: %d reg_base_idx: %d",
+				rc, reg_base_idx);
+			goto end;
+		}
+	}
+end:
+	return rc;
+}
+
 int cam_soc_util_reg_dump_to_cmd_buf(void *ctx,
 	struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id,
-	cam_soc_util_regspace_data_cb reg_data_cb)
+	cam_soc_util_regspace_data_cb reg_data_cb,
+	struct cam_hw_soc_dump_args *soc_dump_args,
+	bool user_triggered_dump)
 {
 	int                               rc = 0, i, j;
 	uintptr_t                         cpu_addr = 0;
@@ -2148,12 +2407,6 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx,
 			goto end;
 		}
 
-		dump_out_buf = (struct cam_reg_dump_out_buffer *)
-			(cmd_buf_start +
-			(uintptr_t)reg_dump_desc->dump_buffer_offset);
-		dump_out_buf->req_id = req_id;
-		dump_out_buf->bytes_written = 0;
-
 		reg_base_type = reg_dump_desc->reg_base_type;
 		if (reg_base_type == 0 || reg_base_type >
 			CAM_REG_DUMP_BASE_TYPE_CAMNOC) {
@@ -2185,6 +2438,31 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx,
 			"Reg data callback success req_id: %llu base_type: %d base_idx: %d num_read_range: %d",
 			req_id, reg_base_type, reg_base_idx,
 			reg_dump_desc->num_read_range);
+
+		/* If the dump request is triggered by user space
+		 * buffer will be different from the buffer which is received
+		 * in init packet. In this case, dump the data to the
+		 * user provided buffer and exit.
+		 */
+		if (user_triggered_dump) {
+			rc = cam_soc_util_user_reg_dump(reg_dump_desc,
+				soc_dump_args, soc_info, reg_base_idx);
+			CAM_INFO(CAM_UTIL,
+				"%s reg_base_idx %d dumped offset %u",
+				soc_info->dev_name, reg_base_idx,
+				soc_dump_args->offset);
+			goto end;
+		}
+
+		/* Below code is executed when data is dumped to the
+		 * out buffer received in init packet
+		 */
+		dump_out_buf = (struct cam_reg_dump_out_buffer *)
+			(cmd_buf_start +
+			(uintptr_t)reg_dump_desc->dump_buffer_offset);
+		dump_out_buf->req_id = req_id;
+		dump_out_buf->bytes_written = 0;
+
 		for (j = 0; j < reg_dump_desc->num_read_range; j++) {
 			CAM_DBG(CAM_UTIL,
 				"Number of bytes written to cmd buffer: %u req_id: %llu",

+ 46 - 11
drivers/cam_utils/cam_soc_util.h

@@ -41,6 +41,9 @@
 #define DDR_TYPE_LPDDR5        8
 #define DDR_TYPE_LPDDR5X       9
 
+/* Maximum length of tag while dumping */
+#define CAM_SOC_HW_DUMP_TAG_MAX_LEN 32
+
 /**
  * enum cam_vote_level - Enum for voting level
  *
@@ -218,6 +221,34 @@ struct cam_hw_soc_info {
 	void                           *soc_private;
 };
 
+/**
+ * struct cam_hw_soc_dump_header - SOC dump header
+ *
+ * @Brief:        soc hw dump header
+ *
+ * @tag:          Tag name for the header
+ * @word_size:    Size of each word
+ * @size:         Total size of dumped data
+ */
+struct cam_hw_soc_dump_header {
+	uint8_t   tag[CAM_SOC_HW_DUMP_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
+/**
+ * struct cam_hw_soc_dump_args:   SOC Dump args
+ *
+ * @request_id:          Issue request id
+ * @offset:              Buffer offset, updated as the informaton is dumped
+ * @buf_handle:          Buffer handle of the out buffer
+ */
+struct cam_hw_soc_dump_args {
+	uint64_t             request_id;
+	size_t               offset;
+	uint32_t             buf_handle;
+};
+
 /*
  * CAM_SOC_GET_REG_MAP_START
  *
@@ -636,19 +667,23 @@ typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type,
 /**
  * cam_soc_util_reg_dump_to_cmd_buf()
  *
- * @brief:              Camera SOC util for dumping sets of register ranges to
- *                      to command buffer
- *
- * @ctx:                Context info from specific hardware manager
- * @cmd_desc:           Command buffer descriptor
- * @req_id:             Last applied req id for which reg dump is required
- * @reg_data_cb:        Callback function to get reg space info based on type
- *                      in command buffer
- *
- * @return:             Success or Failure
+ * @brief:                 Camera SOC util for dumping sets of register ranges
+ *                         command buffer
+ *
+ * @ctx:                   Context info from specific hardware manager
+ * @cmd_desc:              Command buffer descriptor
+ * @req_id:                Last applied req id for which reg dump is required
+ * @reg_data_cb:           Callback function to get reg space info based on type
+ *                         in command buffer
+ * @soc_dump_args:         Dump buffer args to dump the soc information.
+ * @user_triggered_dump:   Flag to indicate if the dump request is issued by
+ *                         user.
+ * @return:                Success or Failure
  */
 int cam_soc_util_reg_dump_to_cmd_buf(void *ctx,
 	struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id,
-	cam_soc_util_regspace_data_cb reg_data_cb);
+	cam_soc_util_regspace_data_cb reg_data_cb,
+	struct cam_hw_soc_dump_args *soc_dump_args,
+	bool user_triggered_dump);
 
 #endif /* _CAM_SOC_UTIL_H_ */