diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 56138c33091d..b7b6ae1bb6b7 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -21,6 +21,9 @@ /* maximum buf done irqs */ #define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12 +/* Maximum reg dump cmd buffer entries in a context */ +#define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 + /* hardware event callback function type */ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, void *evt_data); @@ -166,6 +169,8 @@ struct cam_hw_mgr_dump_pf_data { * @max_in_map_entries: Maximum input fence mapping supported * @in_map_entries: Actual input fence mapping list (returned) * @num_in_map_entries: Number of acutal input fence mapping (returned) + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc * @priv: Private pointer of hw update * @pf_data: Debug data for page fault * @@ -183,6 +188,9 @@ struct cam_hw_prepare_update_args { uint32_t max_in_map_entries; struct cam_hw_fence_map_entry *in_map_entries; uint32_t num_in_map_entries; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; void *priv; struct cam_hw_mgr_dump_pf_data *pf_data; }; @@ -266,6 +274,8 @@ struct cam_hw_dump_pf_args { enum cam_hw_mgr_command { CAM_HW_MGR_CMD_INTERNAL, CAM_HW_MGR_CMD_DUMP_PF_INFO, + CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH, + CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR, }; /** diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index d88adebea4f7..638478cb56e1 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1116,6 +1116,22 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW)) notify.error = CRM_KMD_ERR_OVERFLOW; + + if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_VIOLATION)) { + struct cam_hw_cmd_args hw_cmd_args; + + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on error failed rc: %d", rc); + rc = 0; + } + } /* * The error is likely caused by first request on the active list. * If active list is empty check wait list (maybe error hit as soon @@ -1932,6 +1948,8 @@ static int __cam_isp_ctx_flush_req_in_top_state( { int rc = 0; struct cam_isp_context *ctx_isp; + struct cam_hw_cmd_args hw_cmd_args; + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { @@ -1945,6 +1963,16 @@ static int __cam_isp_ctx_flush_req_in_top_state( rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on flush failed rc: %d", rc); + rc = 0; + } + atomic_set(&ctx_isp->process_bubble, 0); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index faf2fb02e924..96a12a707dd3 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2077,7 +2077,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, ctx = userdata; if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { - complete(&ctx->config_done_complete); + complete_all(&ctx->config_done_complete); CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", handle, userdata, status, cookie, ctx->ctx_index); @@ -3059,8 +3059,8 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd[i].len = cmd->len; } - if (cfg->init_packet) - init_completion(&ctx->config_done_complete); + reinit_completion(&ctx->config_done_complete); + ctx->applied_req_id = cfg->request_id; CAM_DBG(CAM_ISP, "Submit to CDM"); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); @@ -5058,6 +5058,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, prepare->num_hw_update_entries = 0; prepare->num_in_map_entries = 0; prepare->num_out_map_entries = 0; + prepare->num_reg_dump_buf = 0; memset(&prepare_hw_data->bw_config[0], 0x0, sizeof(prepare_hw_data->bw_config[0]) * @@ -5123,6 +5124,15 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (((prepare->packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_INIT_DEV) { prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; + ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; + if ((ctx->num_reg_dump_buf) && (ctx->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + memcpy(ctx->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare->num_reg_dump_buf); + } + goto end; } else prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; @@ -5279,6 +5289,118 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } } +static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, + void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ife_hw_mgr_ctx *ctx = + (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; + + *soc_info_ptr = NULL; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + switch (reg_base_type) { + case CAM_REG_DUMP_BASE_TYPE_CAMNOC: + case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_LEFT, rc); + return rc; + } + + if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) + *reg_base_idx = 0; + else + *reg_base_idx = 1; + + *soc_info_ptr = soc_info; + break; + case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_RIGHT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_RIGHT, rc); + return rc; + } + + *reg_base_idx = 0; + *soc_info_ptr = soc_info; + break; + default: + CAM_ERR(CAM_ISP, + "Unrecognized reg base type: %d", + reg_base_type); + return -EINVAL; + } + } + + return rc; +} + +static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, + uint32_t meta_type) +{ + int rc, i; + + if (!ctx->num_reg_dump_buf) { + CAM_DBG(CAM_ISP, + "Zero command buffers for reg dump req_id: [%llu] ctx idx: [%llu] meta_type: %d", + ctx->applied_req_id, ctx->ctx_index, meta_type); + return 0; + } + + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(30)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout rc=%d ctx_index %d", + rc, ctx->ctx_index); + rc = 0; + } + + for (i = 0; i < ctx->num_reg_dump_buf; i++) { + CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %d req_type: %d", + ctx->reg_dump_buf_desc[i].meta_data, meta_type); + if (ctx->reg_dump_buf_desc[i].meta_data == meta_type) { + rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, + &ctx->reg_dump_buf_desc[i], + ctx->applied_req_id, + cam_ife_mgr_regspace_data_cb); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %d", + i, rc, ctx->applied_req_id, meta_type); + return -EINVAL; + } + } + } + + return 0; +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -5342,6 +5464,37 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH: + if (ctx->last_dump_flush_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_flush_req_id = ctx->applied_req_id; + + rc = cam_ife_mgr_handle_reg_dump(ctx, + CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on flush failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR: + if (ctx->last_dump_err_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_err_req_id = ctx->applied_req_id; + rc = cam_ife_mgr_handle_reg_dump(ctx, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on error failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 16143b014ebf..698b0c60ca9b 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -124,6 +124,11 @@ struct cam_ife_hw_mgr_debug { * context * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * @applied_req_id: Last request id to be applied + * @last_dump_flush_req_id Last req id for which reg dump on flush was called + * @last_dump_err_req_id Last req id for which reg dump on error was called * @init_done indicate whether init hw is done * @is_fe_enable indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode @@ -161,6 +166,12 @@ struct cam_ife_hw_mgr_ctx { atomic_t overflow_pending; uint32_t is_rdi_only_context; struct completion config_done_complete; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; + uint64_t applied_req_id; + uint64_t last_dump_flush_req_id; + uint64_t last_dump_err_req_id; bool init_done; bool is_fe_enable; bool is_dual; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index be098a619aaf..48928bccc472 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -420,6 +420,26 @@ int cam_isp_add_command_buffers( num_ent = prepare->num_hw_update_entries; } break; + case CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH: + case CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + if (prepare->num_reg_dump_buf >= + CAM_REG_DUMP_MAX_BUF_ENTRIES) { + CAM_ERR(CAM_ISP, + "Descriptor count out of bounds: %d", + prepare->num_reg_dump_buf); + return -EINVAL; + } + prepare->reg_dump_buf_desc[ + prepare->num_reg_dump_buf] = + cmd_desc[i]; + prepare->num_reg_dump_buf++; + CAM_DBG(CAM_ISP, + "Added command buffer: %d desc_count: %d", + cmd_desc[i].meta_data, + prepare->num_reg_dump_buf); + } + break; default: CAM_ERR(CAM_ISP, "invalid cdm command meta data %d", cmd_meta_data); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 1e556137996d..741b41d4cccf 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -101,6 +101,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CORE_CONFIG, CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index bbc25bc96045..7e9aa91689c3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -735,6 +735,12 @@ static int cam_vfe_camif_ver3_process_cmd( rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: + camif_priv = (struct cam_vfe_mux_camif_ver3_data *) + rsrc_node->res_priv; + *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; + rc = 0; + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index e32a6ab21665..99e349a66c61 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -11,6 +11,7 @@ #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_cx_ipeak.h" +#include "cam_mem_mgr.h" static char supported_clk_info[256]; static char debugfs_dir_name[64]; @@ -1825,3 +1826,277 @@ int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, return 0; } + +static int cam_soc_util_dump_cont_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_reg_range_read_desc *reg_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) +{ + int i = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK", + soc_info, dump_out_buf); + return -EINVAL; + } + + if (reg_read->num_values >= ((max_out_size - + (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + CAM_ERR(CAM_UTIL, + "Invalid num values to read: %d max values: %d bytes written: %d", + reg_read->num_values, (max_out_size / + sizeof(uint32_t)), dump_out_buf->bytes_written); + return -EINVAL; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < reg_read->num_values; i++) { + dump_out_buf->dump_data[write_idx++] = reg_read->offset + + (i * 4); + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r(soc_info, base_idx, + (reg_read->offset + (i * 4))); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + return 0; +} + +static int cam_soc_util_dump_dmi_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) +{ + int i = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK", + soc_info, dump_out_buf); + return -EINVAL; + } + + 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); + return -EINVAL; + } + + if (dmi_read->dmi_data_read.num_values >= ((max_out_size - + (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + CAM_ERR(CAM_UTIL, + "Invalid num values to read: %d max values: %d bytes written: %d", + dmi_read->dmi_data_read.num_values, (max_out_size / + sizeof(uint32_t)), dump_out_buf->bytes_written); + return -EINVAL; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < dmi_read->num_pre_writes; i++) { + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->pre_read_config[i].offset, + dmi_read->pre_read_config[i].value); + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].offset; + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].value; + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { + dump_out_buf->dump_data[write_idx++] = + dmi_read->dmi_data_read.offset; + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r_mb(soc_info, base_idx, + dmi_read->dmi_data_read.offset); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + for (i = 0; i < dmi_read->num_post_writes; i++) { + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->post_read_config[i].offset, + dmi_read->post_read_config[i].value); + } + + return 0; +} + +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) +{ + int rc = 0, i, j; + uintptr_t cpu_addr = 0; + uintptr_t cmd_buf_start = 0; + uintptr_t cmd_in_data_end = 0; + uintptr_t cmd_buf_end = 0; + uint32_t reg_base_type = 0; + size_t buf_size = 0, remain_len = 0; + size_t max_out_size = 0; + struct cam_reg_dump_input_info *reg_input_info = NULL; + struct cam_reg_dump_desc *reg_dump_desc = NULL; + struct cam_reg_dump_out_buffer *dump_out_buf = NULL; + struct cam_reg_read_info *reg_read_info = NULL; + struct cam_hw_soc_info *soc_info; + uint32_t reg_base_idx = 0; + + if (!ctx || !cmd_desc || !reg_data_cb) { + CAM_ERR(CAM_UTIL, "Invalid args to reg dump [%pK] [%pK]", + cmd_desc, reg_data_cb); + return -EINVAL; + } + + if (!cmd_desc->length || !cmd_desc->size) { + CAM_ERR(CAM_UTIL, "Invalid cmd buf size %d %d", + cmd_desc->length, cmd_desc->size); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &cpu_addr, &buf_size); + if (rc || !cpu_addr || (buf_size == 0)) { + CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", + rc, (void *)cpu_addr); + return rc; + } + + CAM_DBG(CAM_UTIL, "Get cpu buf success req_id: %llu buf_size: %zu", + req_id, buf_size); + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_desc->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_desc->offset); + return -EINVAL; + } + + remain_len = buf_size - (size_t)cmd_desc->offset; + if (remain_len < (size_t)cmd_desc->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_desc->length); + return -EINVAL; + } + + cmd_buf_start = (uintptr_t)(((uint8_t *)cpu_addr) + cmd_desc->offset); + cmd_in_data_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + + cmd_desc->length); + cmd_buf_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + + cmd_desc->size); + if (cmd_buf_end < cmd_in_data_end) { + CAM_ERR(CAM_UTIL, + "Invalid length and size for cmd buf: [%zu] [%zu]", + (size_t)cmd_desc->length, (size_t)cmd_desc->size); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "Buffer params start [%pK] input_end [%pK] buf_end [%pK]", + cmd_buf_start, cmd_in_data_end, cmd_buf_end); + reg_input_info = (struct cam_reg_dump_input_info *) cmd_buf_start; + if (!reg_input_info->num_dump_sets) { + CAM_ERR(CAM_UTIL, "Zero dump sets found in input info"); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "reg_input_info req_id: %llu ctx %pK num_dump_sets: %d", + req_id, ctx, reg_input_info->num_dump_sets); + for (i = 0; i < reg_input_info->num_dump_sets; i++) { + if ((remain_len - sizeof(uint32_t)) <= + (size_t)reg_input_info->dump_set_offsets[i]) { + CAM_ERR(CAM_UTIL, + "Invalid dump set offset: [%zu], remain len: [%zu]", + (size_t)reg_input_info->dump_set_offsets[i], + remain_len); + return -EINVAL; + } + + reg_dump_desc = (struct cam_reg_dump_desc *) + ((uint8_t *)cmd_buf_start + + reg_input_info->dump_set_offsets[i]); + if (!reg_dump_desc->num_read_range) { + CAM_ERR(CAM_UTIL, "Zero ranges found in input info"); + return -EINVAL; + } + + if ((remain_len - sizeof(uint32_t)) + <= (size_t)reg_dump_desc->dump_buffer_offset) { + CAM_ERR(CAM_UTIL, + "Invalid out buffer offset: [%zu], remain len: [%zu]", + (size_t)reg_dump_desc->dump_buffer_offset, + remain_len); + return -EINVAL; + } + + dump_out_buf = (struct cam_reg_dump_out_buffer *) + ((uint8_t *)cmd_buf_start + + reg_dump_desc->dump_buffer_offset); + dump_out_buf->req_id = req_id; + dump_out_buf->bytes_written = 0; + max_out_size = (size_t)(cmd_desc->size - + reg_dump_desc->dump_buffer_offset); + + reg_base_type = reg_dump_desc->reg_base_type; + if (reg_base_type == 0 || reg_base_type > + CAM_REG_DUMP_BASE_TYPE_CAMNOC) { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump base type: %d", + reg_base_type); + return -EINVAL; + } + + rc = reg_data_cb(reg_base_type, ctx, &soc_info, ®_base_idx); + if (rc || !soc_info) { + CAM_ERR(CAM_UTIL, + "Reg space data callback failed rc: %d soc_info: [%pK]", + rc, soc_info); + return -EINVAL; + } + + if (reg_base_idx > soc_info->num_reg_map) { + CAM_ERR(CAM_UTIL, + "Invalid reg base idx: %d num reg map: %d", + reg_base_idx, soc_info->num_reg_map); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "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); + 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", + dump_out_buf->bytes_written, req_id); + reg_read_info = ®_dump_desc->read_range[j]; + if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { + rc = cam_soc_util_dump_cont_reg_range(soc_info, + ®_read_info->reg_read, reg_base_idx, + dump_out_buf, max_out_size); + } else if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_DMI) { + rc = cam_soc_util_dump_dmi_reg_range(soc_info, + ®_read_info->dmi_read, reg_base_idx, + dump_out_buf, max_out_size); + } else { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump read type: %d", + reg_read_info->type); + return -EINVAL; + } + + if (rc) { + CAM_ERR(CAM_UTIL, + "Reg range read failed rc: %d reg_base_idx: %d dump_out_buf: %pK", + rc, reg_base_idx, dump_out_buf); + return rc; + } + } + } + + return 0; +} diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 2ddd4de2d86c..ad2382b835ef 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -18,6 +18,7 @@ #include #include "cam_io_util.h" +#include #define NO_SET_RATE -1 #define INIT_RATE -2 @@ -639,4 +640,27 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, int32_t clk_rate, int clk_idx, int32_t *clk_lvl); +/* Callback to get reg space data for specific HW */ +typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, + void *ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx); + +/** + * 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 + */ +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); + #endif /* _CAM_SOC_UTIL_H_ */