From fa9a698aa107a1dca62054f6278c0e631e58ff49 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 1 Dec 2020 18:30:50 -0800 Subject: [PATCH] msm: camera: isp: Add per frame support for scratch buffers If CRM skips applying settings on a given frame, in case of sHDR program scratch buffers along with RUP/AUP to ensure continuity with respect to sensor frames. CRs-Fixed: 2841729 Change-Id: I296dbc713f49db54681043415b6ad1499dc13de4 Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_hw_mgr_intf.h | 11 +- drivers/cam_isp/cam_isp_context.c | 86 +++++- drivers/cam_isp/cam_isp_context.h | 4 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 253 ++++++++++++++++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 14 +- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 5 +- .../hw_utils/cam_isp_packet_parser.c | 3 +- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 9 +- .../isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c | 19 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 4 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 4 +- .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c | 4 +- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c | 87 +++++- .../isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c | 120 ++++++++- 14 files changed, 565 insertions(+), 58 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 27106aaef0..77d40fc65f 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ @@ -113,9 +113,8 @@ struct cam_hw_done_event_data { * @acquire_info: Acquired resource array pointer * @ctxt_to_hw_map: HW context (returned) * @hw_mgr_ctx_id HWMgr context id(returned) - * @custom_enabled: ctx has custom enabled - * @use_frame_header_ts: Use frame header for qtimer ts - * @support_consumed_addr: The platform has last consumed addr register + * @op_flags: Used as bitwise params from hw_mgr to ctx + * See xxx_hw_mgr_intf.h for definitions * @acquired_hw_id: Acquired hardware mask * @acquired_hw_path: Acquired path mask for an input * if input splits into multiple paths, @@ -132,9 +131,7 @@ struct cam_hw_acquire_args { uintptr_t acquire_info; void *ctxt_to_hw_map; uint32_t hw_mgr_ctx_id; - bool custom_enabled; - bool use_frame_header_ts; - bool support_consumed_addr; + uint32_t op_flags; uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index cf7d8f88f6..5dc1e40ebd 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -3275,6 +3275,32 @@ static int __cam_isp_ctx_apply_req_in_bubble( return rc; } +static int __cam_isp_ctx_apply_default_req_settings( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *isp_ctx = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + + hw_cmd_args.ctxt_to_hw_map = isp_ctx->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = + CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to apply default settings rc %d", rc); + else + CAM_DBG(CAM_ISP, "Applied default settings rc %d", rc); + + return rc; +} + static int __cam_isp_ctx_dump_req_info( struct cam_context *ctx, struct cam_ctx_request *req, @@ -3670,6 +3696,8 @@ static struct cam_ctx_ops .ioctl_ops = {}, .crm_ops = { .apply_req = __cam_isp_ctx_apply_req_in_sof, + .notify_frame_skip = + __cam_isp_ctx_apply_default_req_settings, }, .irq_ops = NULL, }, @@ -3684,6 +3712,8 @@ static struct cam_ctx_ops .ioctl_ops = {}, .crm_ops = { .apply_req = __cam_isp_ctx_apply_req_in_epoch, + .notify_frame_skip = + __cam_isp_ctx_apply_default_req_settings, }, .irq_ops = NULL, }, @@ -3692,6 +3722,8 @@ static struct cam_ctx_ops .ioctl_ops = {}, .crm_ops = { .apply_req = __cam_isp_ctx_apply_req_in_bubble, + .notify_frame_skip = + __cam_isp_ctx_apply_default_req_settings, }, .irq_ops = NULL, }, @@ -4306,6 +4338,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx->last_flush_req = 0; ctx_isp->custom_enabled = false; ctx_isp->use_frame_header_ts = false; + ctx_isp->use_default_apply = false; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -4928,7 +4961,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, } ctx_isp->support_consumed_addr = - param.support_consumed_addr; + (param.op_flags & CAM_IFE_CTX_FRAME_HEADER_EN); /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; @@ -5077,13 +5110,18 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, goto free_res; } - /* Set custom flag if applicable + /* + * Set feature flag if applicable * custom hw is supported only on v2 */ - ctx_isp->custom_enabled = param.custom_enabled; - ctx_isp->use_frame_header_ts = param.use_frame_header_ts; + ctx_isp->custom_enabled = + (param.op_flags & CAM_IFE_CTX_CUSTOM_EN); + ctx_isp->use_frame_header_ts = + (param.op_flags & CAM_IFE_CTX_FRAME_HEADER_EN); + ctx_isp->use_default_apply = + (param.op_flags & CAM_IFE_CTX_APPLY_DEFAULT_CFG); ctx_isp->support_consumed_addr = - param.support_consumed_addr; + (param.op_flags & CAM_IFE_CTX_CONSUME_ADDR_EN); /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; @@ -5761,6 +5799,39 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx, return rc; } +static int __cam_isp_ctx_apply_default_settings( + struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_ctx_ops *ctx_ops = NULL; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (!ctx_isp->use_default_apply) + return 0; + + CAM_DBG(CAM_ISP, + "Enter: apply req in Substate %d request _id:%lld", + ctx_isp->substate_activated, apply->request_id); + + ctx_ops = &ctx_isp->substate_machine[ + ctx_isp->substate_activated]; + if (ctx_ops->crm_ops.notify_frame_skip) { + rc = ctx_ops->crm_ops.notify_frame_skip(ctx, apply); + } else { + CAM_WARN_RATE_LIMIT(CAM_ISP, + "No handle function in activated substate %d", + ctx_isp->substate_activated); + rc = -EFAULT; + } + + if (rc) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Apply default failed in active substate %d rc %d", + ctx_isp->substate_activated, rc); + return rc; +} static int __cam_isp_ctx_handle_irq_in_activated(void *context, @@ -5878,6 +5949,8 @@ static struct cam_ctx_ops .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_activated, .apply_req = __cam_isp_ctx_apply_req, + .notify_frame_skip = + __cam_isp_ctx_apply_default_settings, .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, @@ -6078,6 +6151,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->frame_id = 0; ctx->custom_enabled = false; ctx->use_frame_header_ts = false; + ctx->use_default_apply = false; ctx->active_req_cnt = 0; ctx->reported_req_id = 0; ctx->bubble_frame_cnt = 0; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index c92e97dd40..4142fd6470 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ @@ -270,6 +270,7 @@ struct cam_isp_context_event_record { * @use_frame_header_ts: Use frame header for qtimer ts * @support_consumed_addr: Indicate whether HW has last consumed addr reg * @apply_in_progress Whether request apply is in progress + * @use_default_apply: Use default settings in case of frame skip * @init_timestamp: Timestamp at which this context is initialized * @isp_device_type: ISP device type * @rxd_epoch: Indicate whether epoch has been received. Used to @@ -318,6 +319,7 @@ struct cam_isp_context { bool use_frame_header_ts; bool support_consumed_addr; atomic_t apply_in_progress; + bool use_default_apply; unsigned int init_timestamp; uint32_t isp_device_type; atomic_t rxd_epoch; 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 0c8fde92e7..9cae06e16a 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -4047,6 +4047,9 @@ skip_csid_pxl: } } + if (in_port->dynamic_sensor_switch_en) + ife_ctx->ctx_config |= CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON; + return 0; err: /* release resource at the acquire entry funciton */ @@ -4357,7 +4360,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } cam_cpas_get_cpas_hw_version(&ife_ctx->hw_version); - ife_ctx->custom_config = 0; + ife_ctx->ctx_config = 0; ife_ctx->cdm_handle = 0; ife_ctx->ctx_type = CAM_IFE_CTX_TYPE_NONE; @@ -4420,10 +4423,10 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) if (in_port[i].cust_node) { ife_ctx->ctx_type = CAM_IFE_CTX_TYPE_CUSTOM; /* These can be obtained from uapi */ - ife_ctx->custom_config |= - CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS; - ife_ctx->custom_config |= - CAM_IFE_CUSTOM_CFG_SW_SYNC_ON; + ife_ctx->ctx_config |= + CAM_IFE_CTX_CFG_FRAME_HEADER_TS; + ife_ctx->ctx_config |= + CAM_IFE_CTX_CFG_SW_SYNC_ON; } else if (in_port[i].sfe_in_path_type) { ife_ctx->ctx_type = CAM_IFE_CTX_TYPE_SFE; } @@ -4517,16 +4520,26 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) atomic_set(&ife_ctx->cdm_done, 1); ife_ctx->last_cdm_done_req = 0; - acquire_args->support_consumed_addr = - g_ife_hw_mgr.support_consumed_addr; + if (g_ife_hw_mgr.support_consumed_addr) + acquire_args->op_flags |= + CAM_IFE_CTX_CONSUME_ADDR_EN; + + if ((ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) && + ife_ctx->is_fe_enabled) { + ife_ctx->ctx_config |= CAM_IFE_CTX_CFG_SFE_FE_MODE; + acquire_args->op_flags |= + CAM_IFE_CTX_APPLY_DEFAULT_CFG; + } acquire_args->ctxt_to_hw_map = ife_ctx; - acquire_args->custom_enabled = false; if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_CUSTOM) - acquire_args->custom_enabled = true; - acquire_args->use_frame_header_ts = - (ife_ctx->custom_config & - CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS); + acquire_args->op_flags |= CAM_IFE_CTX_CUSTOM_EN; + + if (ife_ctx->ctx_config & + CAM_IFE_CTX_CFG_FRAME_HEADER_TS) + acquire_args->op_flags |= + CAM_IFE_CTX_FRAME_HEADER_EN; + ife_ctx->ctx_in_use = 1; ife_ctx->num_reg_dump_buf = 0; memset(&ife_ctx->scratch_config, 0, @@ -5374,7 +5387,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, } if (cfg->init_packet || hw_update_data->mup_en || - (ctx->custom_config & CAM_IFE_CUSTOM_CFG_SW_SYNC_ON)) { + (ctx->ctx_config & CAM_IFE_CTX_CFG_SW_SYNC_ON)) { rem_jiffies = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(60)); @@ -6272,7 +6285,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->cdm_ops = NULL; ctx->num_reg_dump_buf = 0; ctx->ctx_type = CAM_IFE_CTX_TYPE_NONE; - ctx->custom_config = 0; + ctx->ctx_config = 0; ctx->num_reg_dump_buf = 0; ctx->is_dual = false; ctx->dsp_enabled = false; @@ -8313,6 +8326,21 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_DYNAMIC_MODE_SWITCH: { + struct cam_isp_mode_switch_info *mup_config; + + if (blob_size < sizeof(struct cam_isp_mode_switch_info)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_mode_switch_info)); + return -EINVAL; + } + + mup_config = (struct cam_isp_mode_switch_info *)blob_data; + ife_mgr_ctx->scratch_config.curr_num_exp = + mup_config->num_expoures; + } + break; case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: @@ -8350,7 +8378,7 @@ static int cam_isp_sfe_send_scratch_buf_upd( memset(io_addr, 0, sizeof(io_addr)); update_buf.res = hw_res; - update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE; + update_buf.cmd_type = cmd_type; update_buf.cmd.cmd_buf_addr = cpu_addr; update_buf.use_scratch_cfg = true; @@ -8380,7 +8408,11 @@ static int cam_isp_sfe_send_scratch_buf_upd( CAM_DBG(CAM_ISP, "Scratch buf configured for: 0x%x", hw_res->res_id); - *used_bytes = update_buf.cmd.used_bytes; + /* Update used bytes if update is via CDM */ + if ((cmd_type == CAM_ISP_HW_CMD_GET_BUF_UPDATE) || + (cmd_type == CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM)) + *used_bytes = update_buf.cmd.used_bytes; + return rc; } @@ -8441,7 +8473,15 @@ static int cam_isp_sfe_add_scratch_buffer_cfg( } res_id = hw_mgr_res->hw_res[j]->res_id; - cpu_addr = kmd_buf_info->cpu_addr + + + /* check for num exposures */ + if ((ctx->ctx_config & + CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON) && + ((res_id - CAM_ISP_SFE_OUT_RES_RDI_0) >= + ctx->scratch_config.curr_num_exp)) + continue; + + cpu_addr = kmd_buf_info->cpu_addr + kmd_buf_info->used_bytes / 4 + io_cfg_used_bytes / 4; buf_info = &ctx->scratch_config.buf_info[ @@ -8487,6 +8527,14 @@ static int cam_isp_sfe_add_scratch_buffer_cfg( } res_id = hw_mgr_res->hw_res[j]->res_id; + + /* check for num exposures */ + if ((ctx->ctx_config & + CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON) && + ((res_id - CAM_ISP_HW_SFE_IN_RD0) >= + ctx->scratch_config.curr_num_exp)) + continue; + cpu_addr = kmd_buf_info->cpu_addr + kmd_buf_info->used_bytes / 4 + io_cfg_used_bytes / 4; @@ -8707,7 +8755,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (rc) return rc; - if (ctx->custom_config & CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS) { + if (ctx->ctx_config & CAM_IFE_CTX_CFG_FRAME_HEADER_TS) { rc = cam_ife_mgr_util_insert_frame_header(&kmd_buf, prepare_hw_data); if (rc) @@ -8825,7 +8873,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, } sfe_fe_chk_cfg.sfe_fe_enabled = false; - if ((ctx->is_fe_enabled) && + if ((!ctx->is_offline) && (ctx->is_fe_enabled) && (ctx->base[i].hw_type == CAM_ISP_HW_TYPE_SFE)) { sfe_fe_chk_cfg.sfe_fe_enabled = true; sfe_fe_chk_cfg.sfe_rdi_cfg_mask = 0; @@ -8899,7 +8947,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, } /* Check if frame header was enabled for any WM */ - if ((ctx->custom_config & CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS) && + if ((ctx->ctx_config & CAM_IFE_CTX_CFG_FRAME_HEADER_TS) && (prepare->num_out_map_entries) && (!prepare_hw_data->frame_header_res_id)) { CAM_ERR(CAM_ISP, "Failed to configure frame header"); @@ -9290,6 +9338,159 @@ outportlog: } +int cam_isp_config_csid_rup_aup( + struct cam_ife_hw_mgr_ctx *ctx) +{ + int rc = 0, i, j, hw_idx; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct list_head *res_list; + struct cam_isp_resource_node *res; + struct cam_isp_csid_reg_update_args + rup_args[CAM_IFE_CSID_HW_NUM_MAX] = {0}; + + res_list = &ctx->res_list_ife_csid; + for (j = 0; j < ctx->num_base; j++) { + if (ctx->base[j].hw_type != CAM_ISP_HW_TYPE_CSID) + continue; + + list_for_each_entry(hw_mgr_res, res_list, list) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != ctx->base[j].idx) + continue; + + hw_idx = res->hw_intf->hw_idx; + rup_args[hw_idx].res[rup_args[hw_idx].num_res] = res; + rup_args[hw_idx].num_res++; + + CAM_DBG(CAM_ISP, + "Reg update for res %d hw_id %d cdm_idx %d", + res->res_id, res->hw_intf->hw_idx, ctx->base[j].idx); + } + } + } + + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!rup_args[i].num_res) + continue; + + rup_args[i].cmd.cmd_buf_addr = NULL; + rup_args[i].cmd.size = 0; + rup_args[i].reg_write = true; + res = rup_args[i].res[0]; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_REG_UPDATE, &rup_args[i], + sizeof(struct cam_isp_csid_reg_update_args)); + if (rc) + return rc; + + CAM_DBG(CAM_ISP, + "Reg update for res %d hw_id %d ", + res->res_id, res->hw_intf->hw_idx); + } + + return rc; +} + +/* + * Scratch buffer is for sHDR usescases involing SFE RDI0-2 + * There is no possibility of dual in this case, hence + * using the scratch buffer provided during INIT corresponding + * to each left RDIs + */ +static int cam_ife_mgr_prog_default_settings( + struct cam_ife_hw_mgr_ctx *ctx) +{ + int i, j, res_id, rc = 0; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_sfe_scratch_buf_info *buf_info; + struct list_head *res_list_in_rd = NULL; + struct cam_isp_hw_mgr_res *res_list_sfe_out = NULL; + + res_list_in_rd = &ctx->res_list_ife_in_rd; + res_list_sfe_out = ctx->res_list_sfe_out; + + for (i = 0; i < CAM_SFE_FE_RDI_NUM_MAX; i++) { + hw_mgr_res = &res_list_sfe_out[i]; + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + /* j = 1 is not valid for this use-case */ + if (!hw_mgr_res->hw_res[j]) + continue; + + res_id = hw_mgr_res->hw_res[j]->res_id; + /* check for num exposures */ + if ((ctx->ctx_config & + CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON) && + ((res_id - CAM_ISP_SFE_OUT_RES_RDI_0) >= + ctx->scratch_config.curr_num_exp)) + continue; + + buf_info = &ctx->scratch_config.buf_info[ + res_id - CAM_ISP_SFE_OUT_RES_RDI_0]; + + CAM_DBG(CAM_ISP, + "RDI%d res_id 0x%x idx %u io_addr %pK", + i, + hw_mgr_res->hw_res[j]->res_id, + (res_id - CAM_ISP_SFE_OUT_RES_RDI_0), + buf_info->io_addr); + + rc = cam_isp_sfe_send_scratch_buf_upd(0x0, + CAM_ISP_HW_CMD_BUF_UPDATE, + hw_mgr_res->hw_res[j], buf_info, + NULL, NULL); + if (rc) + return rc; + } + } + + list_for_each_entry(hw_mgr_res, res_list_in_rd, list) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + res_id = hw_mgr_res->hw_res[j]->res_id; + + /* check for num exposures */ + if ((ctx->ctx_config & + CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON) && + ((res_id - CAM_ISP_HW_SFE_IN_RD0) >= + ctx->scratch_config.curr_num_exp)) + continue; + + buf_info = &ctx->scratch_config.buf_info + [res_id - CAM_ISP_HW_SFE_IN_RD0]; + CAM_DBG(CAM_ISP, + "RD res_id 0x%x idx %u io_addr %pK", + hw_mgr_res->hw_res[j]->res_id, + (res_id - CAM_ISP_HW_SFE_IN_RD0), + buf_info->io_addr); + rc = cam_isp_sfe_send_scratch_buf_upd(0x0, + CAM_ISP_HW_CMD_BUF_UPDATE_RM, + hw_mgr_res->hw_res[j], buf_info, + NULL, NULL); + if (rc) + return rc; + } + } + + /* Program rup & aup */ + rc = cam_isp_config_csid_rup_aup(ctx); + if (rc) + CAM_ERR(CAM_ISP, + "RUP/AUP update failed for scratch buffers"); + + return rc; +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -9359,6 +9560,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) isp_hw_cmd_args->u.last_cdm_done = ctx->last_cdm_done_req; break; + case CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG: + rc = cam_ife_mgr_prog_default_settings(ctx); + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -10248,8 +10452,8 @@ static int cam_ife_hw_mgr_handle_hw_sof( case CAM_ISP_HW_VFE_IN_CAMIF: case CAM_ISP_HW_VFE_IN_RD: /* if frame header is enabled reset qtimer ts */ - if (ife_hw_mgr_ctx->custom_config & - CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS) { + if (ife_hw_mgr_ctx->ctx_config & + CAM_IFE_CTX_CFG_FRAME_HEADER_TS) { sof_done_event_data.timestamp = 0x0; ktime_get_boottime_ts64(&ts); sof_done_event_data.boot_time = @@ -10417,7 +10621,8 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( buf_done_event_data.last_consumed_addr[0] = event_info->reg_val; - if ((ife_hw_mgr_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) && + if ((!ife_hw_mgr_ctx->is_offline) && + (ife_hw_mgr_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) && (ife_hw_mgr_ctx->is_fe_enabled)) { rc = cam_ife_hw_mgr_check_rdi_scratch_buf_done( ife_hw_mgr_ctx, event_info->res_id, 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 6003efed6f..34267c357a 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_HW_MGR_H_ @@ -33,9 +33,11 @@ enum cam_ife_ctx_master_type { #define CAM_SFE_HW_OUT_RES_MAX (CAM_ISP_SFE_OUT_RES_MAX & 0xFF) #define CAM_IFE_HW_RES_POOL_MAX 64 -/* IFE_HW_MGR custom config */ -#define CAM_IFE_CUSTOM_CFG_FRAME_HEADER_TS BIT(0) -#define CAM_IFE_CUSTOM_CFG_SW_SYNC_ON BIT(1) +/* IFE_HW_MGR ctx config */ +#define CAM_IFE_CTX_CFG_FRAME_HEADER_TS BIT(0) +#define CAM_IFE_CTX_CFG_SW_SYNC_ON BIT(1) +#define CAM_IFE_CTX_CFG_SFE_FE_MODE BIT(2) +#define CAM_IFE_CTX_CFG_DYNAMIC_SWITCH_ON BIT(3) #define CAM_IFE_UBWC_COMP_EN BIT(1) @@ -89,12 +91,14 @@ struct cam_sfe_scratch_buf_info { * * @config_done: To indicate if stream received it's scratch cfg * @num_configs: Number of buffer configs [max of 3 currently] + * @curr_num_exp: Current num of exposures * @buf_info: Info on each of the buffers * */ struct cam_sfe_scratch_buf_cfg { bool config_done; uint32_t num_config; + uint32_t curr_num_exp; struct cam_sfe_scratch_buf_info buf_info[ CAM_SFE_FE_RDI_NUM_MAX]; }; @@ -212,7 +216,7 @@ struct cam_ife_hw_mgr_ctx { bool is_fe_enabled; bool is_dual; enum cam_ife_ctx_master_type ctx_type; - uint32_t custom_config; + uint32_t ctx_config; struct timespec64 ts; bool is_tpg; bool is_offline; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index 77b5d2c619..9db0fd5528 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -2037,8 +2037,9 @@ static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) tfe_ctx->ctx_in_use = 1; tfe_ctx->num_reg_dump_buf = 0; - acquire_args->support_consumed_addr = - g_tfe_hw_mgr.support_consumed_addr; + if (g_tfe_hw_mgr.support_consumed_addr) + acquire_args->op_flags |= + CAM_IFE_CTX_CONSUME_ADDR_EN; cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->used_ctx_list, &tfe_ctx); 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 04538859f3..780a3af6bc 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -1723,6 +1723,7 @@ int cam_isp_add_csid_reg_update( kmd_buf_info->used_bytes/4 + reg_update_size/4; rup_args->cmd.size = kmd_buf_remain_size; + rup_args->reg_write = false; res = rup_args->res[0]; rc = res->hw_intf->hw_ops.process_cmd( diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 74bdaca911..50b6876eab 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ @@ -32,6 +32,12 @@ /* Appliacble vote paths for dual ife, based on no. of UAPI definitions */ #define CAM_ISP_MAX_PER_PATH_VOTES 40 +/* Output params for acquire from hw_mgr to ctx */ +#define CAM_IFE_CTX_CUSTOM_EN BIT(0) +#define CAM_IFE_CTX_FRAME_HEADER_EN BIT(1) +#define CAM_IFE_CTX_CONSUME_ADDR_EN BIT(2) +#define CAM_IFE_CTX_APPLY_DEFAULT_CFG BIT(3) + /** * enum cam_isp_hw_event_type - Collection of the ISP hardware events */ @@ -240,6 +246,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_CTX_TYPE, CAM_ISP_HW_MGR_GET_PACKET_OPCODE, CAM_ISP_HW_MGR_GET_LAST_CDM_DONE, + CAM_ISP_HW_MGR_CMD_PROG_DEFAULT_CFG, CAM_ISP_HW_MGR_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c index 867044937f..5b0abdd917 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -3334,6 +3334,7 @@ static int cam_ife_csid_ver2_reg_update( struct cam_isp_csid_reg_update_args *rup_args = cmd_args; struct cam_cdm_utils_ops *cdm_util_ops; struct cam_ife_csid_ver2_reg_info *csid_reg; + struct cam_hw_soc_info *soc_info; uint32_t size, i; uint32_t reg_val_pair[2]; uint32_t rup_aup_mask = 0; @@ -3366,7 +3367,7 @@ static int cam_ife_csid_ver2_reg_update( size = cdm_util_ops->cdm_required_size_reg_random(1); /* since cdm returns dwords, we need to convert it into bytes */ - if ((size * 4) > rup_args->cmd.size) { + if ((!rup_args->reg_write) && ((size * 4) > rup_args->cmd.size)) { CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", rup_args->cmd.size, (size*4)); return -EINVAL; @@ -3420,10 +3421,16 @@ static int cam_ife_csid_ver2_reg_update( csid_hw->hw_intf->hw_idx, reg_val_pair[1], reg_val_pair[0]); - cdm_util_ops->cdm_write_regrandom(rup_args->cmd.cmd_buf_addr, - 1, reg_val_pair); - - rup_args->cmd.used_bytes = size * 4; + if (rup_args->reg_write) { + soc_info = &csid_hw->hw_info->soc_info; + cam_io_w_mb(reg_val_pair[1], + soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base + + reg_val_pair[0]); + } else { + cdm_util_ops->cdm_write_regrandom(rup_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + rup_args->cmd.used_bytes = size * 4; + } return rc; err: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 1f8890389b..be0ca83c51 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSID_HW_INTF_H_ @@ -353,11 +353,13 @@ struct cam_ife_csid_dual_sync_args { * @cmd: cmd buf update args * @node_res: Node res pointer * @num_res: Num of resources + * @reg_write: if set use AHB to config rup/aup */ struct cam_isp_csid_reg_update_args { struct cam_isp_hw_cmd_buf_update cmd; struct cam_isp_resource_node *res[CAM_IFE_PIX_PATH_RES_MAX]; uint32_t num_res; + bool reg_write; }; /* 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 99eb370ae7..e5187c9e40 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_H_ @@ -145,6 +145,8 @@ enum cam_isp_hw_cmd_type { CAM_IFE_CSID_PROGRAM_OFFLINE_CMD, CAM_IFE_CSID_SET_DUAL_SYNC_CONFIG, CAM_ISP_HW_CMD_CSID_MUP_UPDATE, + CAM_ISP_HW_CMD_BUF_UPDATE, + CAM_ISP_HW_CMD_BUF_UPDATE_RM, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c index bf7421ca1e..1d652eba16 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -327,6 +327,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, cmd_args, arg_size); break; case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + case CAM_ISP_HW_CMD_BUF_UPDATE: case CAM_ISP_HW_CMD_GET_HFR_UPDATE: case CAM_ISP_HW_CMD_STRIPE_UPDATE: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: @@ -337,6 +338,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, break; case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + case CAM_ISP_HW_CMD_BUF_UPDATE_RM: case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: rc = core_info->sfe_bus_rd->hw_ops.process_cmd( core_info->sfe_bus_rd->bus_priv, cmd_type, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c index 69878873ec..4b9e8442d4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -1118,6 +1118,88 @@ static int cam_sfe_bus_deinit_sfe_bus_rd_resource( return 0; } +/* + * API similar to cam_sfe_bus_rd_update_rm() with the + * only change being config is done via AHB instead of CDM + */ +static int cam_sfe_bus_rd_config_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_rd_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_sfe_bus_rd_data *sfe_bus_rd_data = NULL; + struct cam_sfe_bus_rd_rm_resource_data *rm_data = NULL; + uint32_t width = 0, height = 0, stride = 0; + uint32_t i; + + bus_priv = (struct cam_sfe_bus_rd_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + sfe_bus_rd_data = (struct cam_sfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!sfe_bus_rd_data || !sfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_SFE, "num of RM: %d scratch_buf_cfg: %s", + sfe_bus_rd_data->num_rm, + update_buf->use_scratch_cfg ? "true" : "false"); + if (update_buf->rm_update->num_buf != sfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_SFE, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + sfe_bus_rd_data->num_rm); + return -EINVAL; + } + + for (i = 0; i < sfe_bus_rd_data->num_rm; i++) { + rm_data = sfe_bus_rd_data->rm_res[i]->res_priv; + + stride = update_buf->rm_update->stride; + width = update_buf->rm_update->width; + height = update_buf->rm_update->height; + + /* update size register */ + cam_sfe_bus_rd_pxls_to_bytes(width, + rm_data->unpacker_cfg, &rm_data->width); + rm_data->height = height; + + cam_io_w_mb(rm_data->width, + rm_data->common_data->mem_base + + rm_data->hw_regs->buf_width); + cam_io_w_mb(rm_data->height, + rm_data->common_data->mem_base + + rm_data->hw_regs->buf_height); + + CAM_DBG(CAM_SFE, "SFE:%d RM:%d width:0x%X height:0x%X", + rm_data->common_data->core_index, + rm_data->index, rm_data->width, + rm_data->height); + + rm_data->stride = stride; + cam_io_w_mb(stride, + rm_data->common_data->mem_base + + rm_data->hw_regs->stride); + CAM_DBG(CAM_SFE, "SFE:%d RM:%d image_stride:0x%X", + rm_data->common_data->core_index, + rm_data->index, stride); + + cam_io_w_mb(update_buf->rm_update->image_buf[i], + rm_data->common_data->mem_base + + rm_data->hw_regs->image_addr); + CAM_DBG(CAM_SFE, "SFE:%d RM:%d image_address:0x%X", + rm_data->common_data->core_index, + rm_data->index, + update_buf->rm_update->image_buf[i]); + rm_data->img_addr = + update_buf->rm_update->image_buf[i]; + } + + return 0; +} + static int cam_sfe_bus_rd_update_rm(void *priv, void *cmd_args, uint32_t arg_size) { @@ -1320,6 +1402,9 @@ static int cam_sfe_bus_rd_process_cmd( case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: rc = cam_sfe_bus_rd_update_rm(priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_BUF_UPDATE_RM: + rc = cam_sfe_bus_rd_config_rm(priv, cmd_args, arg_size); + break; case CAM_ISP_HW_CMD_GET_SECURE_MODE: rc = cam_sfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c index a043f60fce..5bb8ccbe89 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ @@ -2074,6 +2074,121 @@ static int cam_sfe_bus_wr_update_wm(void *priv, void *cmd_args, return 0; } +/* + * API similar to cam_sfe_bus_wr_update_wm() with the + * only change being config is done via AHB instead of CDM + */ +static int cam_sfe_bus_wr_config_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_sfe_bus_wr_out_data *sfe_out_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + uint32_t i, k; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0, stride = 0, slice_h = 0; + + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + sfe_out_data = (struct cam_sfe_bus_wr_out_data *) + update_buf->res->res_priv; + + if (!sfe_out_data || !sfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != sfe_out_data->num_wm) { + CAM_ERR(CAM_SFE, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, sfe_out_data->num_wm); + return -EINVAL; + } + + for (i = 0; i < sfe_out_data->num_wm; i++) { + wm_data = (struct cam_sfe_bus_wr_wm_resource_data *) + sfe_out_data->wm_res[i].res_priv; + + val = (wm_data->height << 16) | wm_data->width; + cam_io_w_mb(val, + wm_data->common_data->mem_base + + wm_data->hw_regs->image_cfg_0); + CAM_DBG(CAM_SFE, "WM:%d image height and width 0x%X", + wm_data->index, val); + + /* For initial configuration program all bus registers */ + stride = update_buf->wm_update->stride; + slice_h = update_buf->wm_update->slice_height; + + val = stride; + CAM_DBG(CAM_SFE, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != stride && + val != wm_data->stride) + CAM_WARN(CAM_SFE, "Warning stride %u expected %u", + stride, val); + + if (wm_data->stride != val || !wm_data->init_cfg_done) { + cam_io_w_mb(stride, + wm_data->common_data->mem_base + + wm_data->hw_regs->image_cfg_2); + wm_data->stride = val; + CAM_DBG(CAM_SFE, "WM:%d image stride 0x%X", + wm_data->index, val); + } + + frame_inc = stride * slice_h; + + if (!(wm_data->en_cfg & (0x3 << 16))) { + cam_io_w_mb(wm_data->h_init, + wm_data->common_data->mem_base + + wm_data->hw_regs->image_cfg_1); + CAM_DBG(CAM_SFE, "WM:%d h_init 0x%X", + wm_data->index, wm_data->h_init); + } + + if (wm_data->index > 7) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_cfg & (0x3 << 16)) + cam_io_w_mb((update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc), + wm_data->common_data->mem_base + + wm_data->hw_regs->image_addr); + else + cam_io_w_mb((update_buf->wm_update->image_buf[i] + + k * frame_inc), + wm_data->common_data->mem_base + + wm_data->hw_regs->image_addr); + } + + cam_io_w_mb(frame_inc, + wm_data->common_data->mem_base + + wm_data->hw_regs->frame_incr); + CAM_DBG(CAM_SFE, "WM:%d frame_inc %d", + wm_data->index, frame_inc); + + /* enable the WM */ + cam_io_w_mb(wm_data->en_cfg, + wm_data->common_data->mem_base + + wm_data->hw_regs->cfg); + CAM_DBG(CAM_SFE, "WM:%d en_cfg 0x%X", + wm_data->index, wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + return 0; +} + static int cam_sfe_bus_wr_update_hfr(void *priv, void *cmd_args, uint32_t arg_size) { @@ -2330,6 +2445,9 @@ static int cam_sfe_bus_wr_process_cmd( case CAM_ISP_HW_CMD_GET_BUF_UPDATE: rc = cam_sfe_bus_wr_update_wm(priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_BUF_UPDATE: + rc = cam_sfe_bus_wr_config_wm(priv, cmd_args, arg_size); + break; case CAM_ISP_HW_CMD_GET_HFR_UPDATE: rc = cam_sfe_bus_wr_update_hfr(priv, cmd_args, arg_size); break;