msm: camera: Add support for reg dump to command buffers

Certain register values are required by user space during flush
to apply settings accordingly. Also, support for dumping registers
at the time of error is needed for debugging. Add support for
dumping register values in a range of offsets to given cmd buffer.

Change-Id: I5912118809f7a7dd701a555639d1057ffe665ce1
Signed-off-by: Mukund Madhusudan Atre <matre@codeaurora.org>
This commit is contained in:
Mukund Madhusudan Atre 2019-08-08 15:46:47 -07:00
parent 632d56473b
commit 827791eafa
9 changed files with 531 additions and 3 deletions

View File

@ -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,
};
/**

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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);

View File

@ -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,
};

View File

@ -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);

View File

@ -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, &reg_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 = &reg_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,
&reg_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,
&reg_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;
}

View File

@ -18,6 +18,7 @@
#include <linux/of_fdt.h>
#include "cam_io_util.h"
#include <uapi/media/cam_defs.h>
#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_ */