diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index b742152775..d435a163e1 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -182,6 +182,33 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, return rc; } +int cam_context_handle_crm_signal_buf_done(struct cam_context *ctx, + struct cam_req_mgr_signal_info *state_info) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!state_info) { + CAM_ERR(CAM_CORE, "Invalid change state payload"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].crm_ops.signal_buf_done) { + rc = ctx->state_machine[ctx->state].crm_ops.signal_buf_done(ctx, + state_info); + } else { + CAM_ERR(CAM_CORE, "No crm change state req in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + + return rc; +} + int cam_context_handle_crm_state_change(struct cam_context *ctx, struct cam_req_mgr_request_change_state *state_info) { diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 1b3f1bb58f..731eef07eb 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -130,6 +130,7 @@ struct cam_ctx_ioctl_ops { * @process_evt: Handle event notification from CRM.(optional) * @dump_req: Dump information for the issue request * @change_state: Change sub-state of hw context layer to bubble + * @signal_buf_done Notify device to signal buf done * */ struct cam_ctx_crm_ops { @@ -151,6 +152,8 @@ struct cam_ctx_crm_ops { struct cam_req_mgr_dump_info *dump); int (*change_state)(struct cam_context *ctx, struct cam_req_mgr_request_change_state *change_state); + int (*signal_buf_done)(struct cam_context *ctx, + struct cam_req_mgr_signal_info *signal_info); }; @@ -342,6 +345,18 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, int cam_context_handle_crm_state_change(struct cam_context *ctx, struct cam_req_mgr_request_change_state *state_info); +/** + * cam_context_handle_crm_signal_buf_done() + * + * @brief: Handle signal buf done command + * + * @ctx: Object pointer for cam_context + * @signal_info Signal buf done request command payload + * + */ +int cam_context_handle_crm_signal_buf_done(struct cam_context *ctx, + struct cam_req_mgr_signal_info *signal_info); + /** * cam_context_handle_crm_notify_frame_skip() * diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 11ba559748..7d17f92b64 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -619,6 +619,24 @@ static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush) return cam_context_handle_crm_flush_req(ctx, flush); } +static int __cam_req_mgr_signal_buf_done( + struct cam_req_mgr_signal_info *signal_buf_done_info) +{ + struct cam_context *ctx = NULL; + + if (!signal_buf_done_info) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(signal_buf_done_info->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + signal_buf_done_info->dev_hdl); + return -EINVAL; + } + + return cam_context_handle_crm_signal_buf_done(ctx, signal_buf_done_info); +} + static int __cam_node_crm_state_change_req( struct cam_req_mgr_request_change_state *state_info) { @@ -734,6 +752,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, node->crm_node_intf.notify_frame_skip = __cam_node_crm_notify_frame_skip; node->crm_node_intf.change_state = __cam_node_crm_state_change_req; + node->crm_node_intf.signal_buf_done = __cam_req_mgr_signal_buf_done; mutex_init(&node->list_mutex); INIT_LIST_HEAD(&node->free_ctx_list); diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 3bf6429a5a..4eef2fb5b1 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -98,6 +98,87 @@ static void __cam_isp_ctx_update_event_record( ctx_isp->event_record[event][iterator].timestamp = cur_time; } +static int cam_isp_ctx_sync_signal_on_buf_done_ready( + struct cam_context *ctx, + struct cam_ctx_request *req, + uint32_t status, uint32_t event_cause) +{ + struct cam_isp_ctx_req *req_isp; + int k = 0, rc = 0; + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (!req_isp->buf_done_mask) + return rc; + + for (k = 0; k < req_isp->num_fence_map_out; k++) { + if (req_isp->buf_done_mask & (1 << k)) { + rc = cam_sync_signal(req_isp->fence_map_out[k].sync_id, + status, event_cause); + if (rc) { + CAM_ERR(CAM_ISP, + "ctx[%d] : Sync signal for Req %llu, sync_id %d status=%d failed with rc = %d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[k].sync_id, + status, rc); + return rc; + } else { + CAM_DBG(CAM_ISP, + "ctx[%d] : Sync signal success for Req %llu, sync_id %d status=%d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[k].sync_id, status); + req_isp->fence_map_out[k].sync_id = -1; + } + } + } + req_isp->buf_done_mask = 0; + + return rc; +} + +static int cam_isp_ctx_handle_sync_signal( + struct cam_context *ctx, + struct cam_ctx_request *req, int32_t sync_index, + uint32_t status, uint32_t event_cause) +{ + struct cam_isp_ctx_req *req_isp; + int32_t buf_done_ready = 0; + int rc = 0; + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + buf_done_ready = atomic_read(&req_isp->buf_done_ready); + + if (buf_done_ready != INIT_BUF_DONE) { + rc = cam_isp_ctx_sync_signal_on_buf_done_ready( + ctx, req, status, event_cause); + if (rc) { + CAM_DBG(CAM_ISP, + "Sync failed with rc = %d", rc); + return rc; + } + rc = cam_sync_signal(req_isp->fence_map_out[sync_index].sync_id, + status, + event_cause); + if (rc) { + CAM_DBG(CAM_ISP, + "ctx[%d] :Sync failed Req %llu, sync_id %d status %d with rc = %d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[sync_index].sync_id, + status, rc); + return rc; + } + CAM_DBG(CAM_ISP, + "ctx[%d] : Sync signal success for Req %llu, sync_id %d status %d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[sync_index].sync_id, + status); + req_isp->fence_map_out[sync_index].sync_id = -1; + } else { + req_isp->buf_done_mask |= 1 << sync_index; + } + return rc; +} + static int __cam_isp_ctx_dump_event_record( struct cam_isp_context *ctx_isp, uintptr_t cpu_addr, @@ -836,6 +917,7 @@ static int __cam_isp_ctx_handle_buf_done_for_req_list( atomic_set(&ctx_isp->process_bubble, 0); req_isp->cdm_reset_before_apply = false; ctx_isp->bubble_frame_cnt = 0; + atomic_set(&req_isp->buf_done_ready, 0); if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) @@ -866,6 +948,11 @@ static int __cam_isp_ctx_handle_buf_done_for_req_list( CAM_REQ_MGR_SOF_EVENT_SUCCESS); } } + + rc = cam_isp_ctx_sync_signal_on_buf_done_ready( + ctx, req, CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); req_isp->reapply = false; @@ -961,19 +1048,29 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (!req_isp->bubble_detected) { - CAM_DBG(CAM_ISP, - "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", - req->request_id, - req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id, - ctx->ctx_id); - - rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, - CAM_SYNC_STATE_SIGNALED_SUCCESS, - CAM_SYNC_COMMON_EVENT_SUCCESS); - if (rc) - CAM_DBG(CAM_ISP, "Sync failed with rc = %d", - rc); + if (req_isp->is_sync_mode) { + CAM_DBG(CAM_ISP, + "Hold sync signal: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + rc = cam_isp_ctx_handle_sync_signal(ctx, req, j, + CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + } else { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + if (rc) + CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); + } } else if (!req_isp->bubble_report) { CAM_DBG(CAM_ISP, "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", @@ -1075,18 +1172,21 @@ static int __cam_isp_handle_deferred_buf_done( "ctx[%d] : Req %llu, status=%d res=0x%x should never happen", ctx->ctx_id, req->request_id, status, req_isp->fence_map_out[j].resource_handle); - - rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, - status, event_cause); - if (rc) { - CAM_ERR(CAM_ISP, - "ctx[%d] : Sync signal for Req %llu, sync_id %d status=%d failed with rc = %d", - ctx->ctx_id, req->request_id, - req_isp->fence_map_out[j].sync_id, - status, rc); + if (req_isp->is_sync_mode) { + rc = cam_isp_ctx_handle_sync_signal( + ctx, req, j, status, event_cause); } else { - req_isp->num_acked++; - req_isp->fence_map_out[j].sync_id = -1; + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + status, event_cause); + if (rc) { + CAM_ERR(CAM_ISP, + "ctx[%d] : Sync signal for Req %llu, sync_id %d status=%d failed with rc = %d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[j].sync_id, + status, rc); + } else { + req_isp->num_acked++; + } } } else { req_isp->num_acked++; @@ -1190,16 +1290,27 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( req_isp->fence_map_out[j].sync_id); continue; } else if (!req_isp->bubble_detected) { - CAM_DBG(CAM_ISP, - "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", - req->request_id, - req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id, - ctx->ctx_id); - - rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, - CAM_SYNC_STATE_SIGNALED_SUCCESS, - CAM_SYNC_COMMON_EVENT_SUCCESS); + if (req_isp->is_sync_mode) { + CAM_DBG(CAM_ISP, + "Hold sync signal: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + rc = cam_isp_ctx_handle_sync_signal(ctx, req, j, + CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + } else { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + } if (rc) { CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); @@ -1258,7 +1369,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( req_isp->fence_map_out[j].sync_id, ctx->ctx_id); if (!rc) { req_isp->num_acked++; - req_isp->fence_map_out[j].sync_id = -1; } if ((ctx_isp->use_frame_header_ts) && @@ -1666,10 +1776,11 @@ static int __cam_isp_ctx_reg_upd_in_applied_state( struct cam_isp_context *ctx_isp, void *evt_data) { int rc = 0; - struct cam_ctx_request *req; - struct cam_context *ctx = ctx_isp->base; - struct cam_isp_ctx_req *req_isp; - uint64_t request_id = 0; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + struct cam_req_mgr_notify_rup notify_rup_info; if (list_empty(&ctx->wait_req_list)) { CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); @@ -1684,10 +1795,20 @@ static int __cam_isp_ctx_reg_upd_in_applied_state( if (req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - request_id = req->request_id; + + if (req_isp->is_sync_mode) { + request_id = req->request_id; + notify_rup_info.link_hdl = ctx->link_hdl; + notify_rup_info.req_id = request_id; + ctx->ctx_crm_intf->notify_rup(¬ify_rup_info); + atomic_set(&req_isp->buf_done_ready, notify_rup_info.state); + } + CAM_DBG(CAM_REQ, - "move request %lld to active list(cnt = %d), ctx %u link %x", + "move request %lld to active list(cnt = %d), state %d sync mode %d ctx %u link %x", req->request_id, ctx_isp->active_req_cnt, + notify_rup_info.state, + req_isp->is_sync_mode, ctx->ctx_id, ctx->link_hdl); __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_RUP, req); @@ -1823,6 +1944,7 @@ notify_only: */ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { notify.link_hdl = ctx->link_hdl; notify.dev_hdl = ctx->dev_hdl; @@ -1833,6 +1955,15 @@ notify_only: notify.sof_boottime = ctx_isp->boot_timestamp; notify.trigger_id = ctx_isp->trigger_id; + if (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + notify.fps = req_isp->hw_update_data.fps; + } else { + notify.fps = 0; + } + ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", ctx_isp->frame_id, ctx->ctx_id); @@ -2071,6 +2202,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, if (rc) { req_isp->bubble_detected = false; req_isp->reapply = false; + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_APPLIED; CAM_DBG(CAM_ISP, "Disable bubble for ctx %d link %d", ctx->ctx_id, ctx->link_hdl); return 0; @@ -3229,6 +3362,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } req_isp->bubble_report = apply->report_if_bubble; + req_isp->is_sync_mode = apply->is_sync_mode; cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; cfg.request_id = req->request_id; @@ -3280,6 +3414,40 @@ end: return rc; } +static int __cam_isp_ctx_signal_buf_done( + struct cam_context *ctx, + struct cam_req_mgr_signal_info *signal_buf_done) +{ + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp = NULL; + + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, + list); + if (req->request_id == signal_buf_done->req_id) { + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + atomic_set(&req_isp->buf_done_ready, signal_buf_done->state); + goto end; + } + } + + if (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, + list); + if (req->request_id == signal_buf_done->req_id) { + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + atomic_set(&req_isp->buf_done_ready, signal_buf_done->state); + goto end; + } + } + + CAM_WARN(CAM_ISP, "Request %lld not found", signal_buf_done->req_id); +end: + return 0; +} + static int __cam_isp_ctx_change_substate( struct cam_context *ctx, struct cam_req_mgr_request_change_state *state_info) @@ -3865,6 +4033,7 @@ static struct cam_ctx_ops .ioctl_ops = {}, .crm_ops = { .change_state = __cam_isp_ctx_change_substate, + .signal_buf_done = __cam_isp_ctx_signal_buf_done, }, .irq_ops = NULL, }, @@ -3876,6 +4045,7 @@ static struct cam_ctx_ops .notify_frame_skip = __cam_isp_ctx_apply_default_req_settings, .change_state = __cam_isp_ctx_change_substate, + .signal_buf_done = __cam_isp_ctx_signal_buf_done, }, .irq_ops = NULL, }, @@ -3895,6 +4065,7 @@ static struct cam_ctx_ops .ioctl_ops = {}, .crm_ops = { .change_state = __cam_isp_ctx_change_substate, + .signal_buf_done = __cam_isp_ctx_signal_buf_done, }, .irq_ops = NULL, }, @@ -4789,6 +4960,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( cfg.pf_data = &(req->pf_data); cfg.num_out_map_entries = 0; cfg.num_in_map_entries = 0; + req_isp->hw_update_data.fps = -1; CAM_DBG(CAM_ISP, "try to prepare config packet......"); @@ -4808,6 +4980,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( req_isp->bubble_detected = false; req_isp->cdm_reset_before_apply = false; req_isp->hw_update_data.packet = packet; + atomic_set(&req_isp->buf_done_ready, INIT_BUF_DONE); for (i = 0; i < req_isp->num_fence_map_out; i++) { rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id); @@ -6063,6 +6236,33 @@ static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx, return rc; } +static int __cam_isp_ctx_signal_buf_done_req(struct cam_context *ctx, + struct cam_req_mgr_signal_info *signal_buf_done) +{ + int rc = 0; + struct cam_ctx_ops *ctx_ops = NULL; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "Enter: signal buf done ctx id %d link 0x%x", + ctx->ctx_id, ctx->link_hdl); + ctx_ops = &ctx_isp->substate_machine[ctx_isp->substate_activated]; + if (ctx_ops->crm_ops.signal_buf_done) { + rc = ctx_ops->crm_ops.signal_buf_done(ctx, signal_buf_done); + } else { + CAM_WARN_RATE_LIMIT(CAM_ISP, + "No handle function in activated Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = -EFAULT; + } + + if (rc) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "signal buf done failed"); + return rc; +} + static int __cam_isp_ctx_change_state_req(struct cam_context *ctx, struct cam_req_mgr_request_change_state *state_info) { @@ -6277,6 +6477,7 @@ static struct cam_ctx_ops .process_evt = __cam_isp_ctx_process_evt, .dump_req = __cam_isp_ctx_dump_in_top_state, .change_state = __cam_isp_ctx_change_state_req, + .signal_buf_done = __cam_isp_ctx_signal_buf_done_req, }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_requests, diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 3a1371a07b..e787498331 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -157,7 +157,9 @@ struct cam_isp_ctx_irq_ops { * @reapply: True if reapplying after bubble * @cdm_reset_before_apply: For bubble re-apply when buf done not coming set * to True - * + * @buf_done_ready Flag to check if ready to signal buf done when in sync mode + * @buf_done_mask Mask used to check number of buf done which is yet to be signaled + * @is_sync_mode If request need to be apply in sync with other link */ struct cam_isp_ctx_req { struct cam_ctx_request *base; @@ -177,6 +179,9 @@ struct cam_isp_ctx_req { bool bubble_detected; bool reapply; bool cdm_reset_before_apply; + atomic_t buf_done_ready; + int32_t buf_done_mask; + bool is_sync_mode; }; /** @@ -273,6 +278,7 @@ struct cam_isp_context_event_record { * @workq: Worker thread for offline ife * @trigger_id: ID provided by CRM for each ctx on the link * @last_bufdone_err_apply_req_id: last bufdone error apply request id + * @fps: Current FPS for the activated state. * */ struct cam_isp_context { @@ -321,6 +327,7 @@ struct cam_isp_context { struct cam_req_mgr_core_workq *workq; int32_t trigger_id; int64_t last_bufdone_err_apply_req_id; + uint32_t fps; }; /** 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 7cf78a69ba..e61864b140 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 @@ -8767,6 +8767,27 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, "BW limit update failed for IFE rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG: { + struct cam_fps_config *fps_config; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (blob_size < sizeof(struct cam_fps_config)) { + CAM_ERR(CAM_ISP, "Invalid fps blob size %u expected %u", + blob_size, sizeof(struct cam_fps_config)); + return -EINVAL; + } + + fps_config = (struct cam_fps_config *)blob_data; + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + if (fps_config->fps) { + prepare_hw_data->fps = fps_config->fps; + CAM_DBG(CAM_ISP, "FPS value %u", fps_config->fps); + } else + CAM_WARN(CAM_ISP, "FPS value 0"); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; @@ -9205,6 +9226,7 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data, case CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_BLANKING_CONFIG: case CAM_ISP_GENERIC_BLOB_TYPE_TPG_CORE_CONFIG: case CAM_ISP_GENERIC_BLOB_TYPE_DISCARD_INITIAL_FRAMES: + case CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG: break; default: CAM_WARN(CAM_ISP, "Invalid blob type: %u", blob_type); 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 9322cd4fe8..2e9a6c6d8d 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 @@ -155,6 +155,7 @@ struct cam_isp_bw_config_internal { * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc * @packet CSL packet from user mode driver * @mup_en Flag if dynamic sensor switch is enabled + * @fps: Fps vaue associated with this packet/request * */ struct cam_isp_prepare_hw_update_data { @@ -172,6 +173,7 @@ struct cam_isp_prepare_hw_update_data { uint32_t num_reg_dump_buf; struct cam_packet *packet; bool mup_en; + int32_t fps; }; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 68fe95964a..75fe950fc1 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -18,7 +18,10 @@ #include "cam_req_mgr_debug.h" #include "cam_common_util.h" -#define THRESHOLD_FACTOR 3 +#define THRESHOLD_FACTOR_3 3 +#define THRESHOLD_FACTOR_2 2 +#define MILLI_SECOND_CONVERSION_FACTOR 1000000 +#define CAM_REQ_MGR_DEFAULT_FPS 30 static struct cam_req_mgr_core_device *g_crm_core_dev; static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; @@ -69,6 +72,9 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->sync_frame_id = 0; link->is_sync_req = true; link->skip_sync_apply = false; + link->fps = CAM_REQ_MGR_DEFAULT_FPS; + link->num_isp_dev = 0; + link->retry_threshold = 0; atomic_set(&link->eof_event_cnt, 0); for (pd = 0; pd < CAM_PIPELINE_DELAY_MAX; pd++) { @@ -611,6 +617,7 @@ static void __cam_req_mgr_flush_req_slot( atomic_set(&link->eof_event_cnt, 0); in_q->wr_idx = 0; in_q->rd_idx = 0; + link->sync_frame_id = 0; link->trigger_cnt[0][0] = 0; link->trigger_cnt[0][1] = 0; link->trigger_cnt[1][0] = 0; @@ -898,6 +905,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, struct cam_req_mgr_link_evt_data evt_data; struct cam_req_mgr_tbl_slot *slot = NULL; struct cam_req_mgr_apply *apply_data = NULL; + struct cam_req_mgr_slot *in_q_slot = NULL; apply_req.link_hdl = link->link_hdl; apply_req.report_if_bubble = 0; @@ -1083,6 +1091,10 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, continue; apply_req.trigger_point = trigger; + in_q_slot = &link->req.in_q->slot[idx]; + apply_req.is_sync_mode = + (in_q_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) ? true : false; + CAM_DBG(CAM_REQ, "SEND: link_hdl %x dev %s pd %d req_id %lld", link->link_hdl, dev->dev_info.name, @@ -1522,7 +1534,8 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } if (link->num_sync_link && - (link->initial_sync_req == slot->req_id)) { + ((link->initial_sync_req == slot->req_id) || + ((link->initial_sync_req < slot->req_id) && link->sync_frame_id == 0))) { link->sync_frame_id = trigger_data->frame_id; CAM_DBG(CAM_CRM, "link %x sync frame %lld", link->link_hdl, link->sync_frame_id); @@ -2795,12 +2808,6 @@ int cam_req_mgr_process_error(void *priv, void *data) __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); in_q->rd_idx = idx; in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; - if (link->sync_link[0]) { - in_q->slot[idx].sync_mode = 0; - __cam_req_mgr_inc_idx(&idx, 1, - link->req.l_tbl->num_slots); - in_q->slot[idx].sync_mode = 0; - } /* The next req may also be applied */ idx = in_q->rd_idx; @@ -3081,6 +3088,44 @@ end: return rc; } +static int cam_req_mgr_cb_notify_rup( + struct cam_req_mgr_notify_rup *rup_info) +{ + int i, j, rc = 0; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_connected_device *dev = NULL; + struct cam_req_mgr_signal_info set_signal_flag; + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(rup_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", rup_info->link_hdl); + rc = -EINVAL; + goto end; + } + + if (link->is_master) { + for (i = 0; i < link->num_sync_link; i++) { + for (j = 0; j < link->sync_link[i]->num_devs; j++) { + dev = &link->sync_link[i]->l_dev[j]; + if (dev->ops->signal_buf_done) { + set_signal_flag.link_hdl = link->sync_link[i]->link_hdl; + set_signal_flag.dev_hdl = dev->dev_hdl; + set_signal_flag.req_id = rup_info->req_id; + set_signal_flag.state = SIGNAL_SYNC_BUF_DONE; + dev->ops->signal_buf_done(&set_signal_flag); + } + } + } + rup_info->state = SIGNAL_SYNC_BUF_DONE; + } else { + rup_info->state = INIT_BUF_DONE; + } + +end: + return rc; +} + /** * cam_req_mgr_cb_notify_err() * @@ -3096,7 +3141,7 @@ static bool cam_req_mgr_cb_notify_err( { bool rc = false; int i, j; - uint32_t idx; + int32_t idx; struct crm_workq_task *task = NULL; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_error_notify *notify_err; @@ -3164,6 +3209,7 @@ static bool cam_req_mgr_cb_notify_err( tmp_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && !link->is_master) { crm_timer_reset(link->watchdog); + link->frame_id = err_info->frame_id; CAM_DBG(CAM_CRM, "Not processing bubble as it is slave link %x", link->link_hdl); return true; @@ -3220,6 +3266,7 @@ static bool cam_req_mgr_cb_notify_err( link->sync_link[i]->link_hdl; notify_err->dev_hdl = dev->dev_hdl; notify_err->error = err_info->error; + notify_err->trigger = err_info->trigger; task->process_cb = &cam_req_mgr_process_error; cam_req_mgr_workq_enqueue_task( @@ -3555,6 +3602,12 @@ static int cam_req_mgr_cb_notify_trigger( if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) crm_timer_reset(link->watchdog); + if (link->sof_timestamp == trigger_data->sof_timestamp_val) { + CAM_DBG(CAM_CRM, + "Irq delay, skipping apply"); + return 0; + } + link->prev_sof_timestamp = link->sof_timestamp; link->sof_timestamp = trigger_data->sof_timestamp_val; link->frame_id = trigger_data->frame_id; @@ -3582,7 +3635,6 @@ static int cam_req_mgr_cb_notify_trigger( link->link_hdl, slot->req_id, sync_id, slot->status); } - CAM_DBG(CAM_CRM, "link %x req %lld slot mode %d tmp slot mode %d init sync %lld", link->link_hdl, slot->req_id, @@ -3617,13 +3669,14 @@ static int cam_req_mgr_cb_notify_trigger( frame_duration = (curr_boot_timestamp - link->sof_boottime) * 2; + CAM_DBG(CAM_CRM, "[Master %x] epoch time %lld sof boottime %lld frame id %lld frame duration %d ms open cnt %d req id %lld", link->link_hdl, curr_boot_timestamp, link->sof_boottime, trigger_data->frame_id, - frame_duration/1000000, + frame_duration / MILLI_SECOND_CONVERSION_FACTOR, link->open_req_cnt, slot->req_id); @@ -3721,21 +3774,74 @@ static int cam_req_mgr_cb_notify_trigger( dev_data.timestamp - link->sof_timestamp : link->sof_timestamp - dev_data.timestamp; - threshold = frame_duration / THRESHOLD_FACTOR; /* Checking if master and sync links are in * same frame duration considering master frame * duration in calculating threshold value */ + + if (trigger_data->fps == 0) { + frame_duration = + link->fps * MILLI_SECOND_CONVERSION_FACTOR; + if (link->retry_threshold) { + /* Increase threshold value by dividing frame + * duration with 2, so that sync logic get chance + * to reduce sof time difference in next 3 requests. + */ + link->retry_threshold -= 1; + threshold = frame_duration / THRESHOLD_FACTOR_2; + } else { + /* Normal threshold calculation by dividing frame + * duration with 3 + */ + threshold = frame_duration / THRESHOLD_FACTOR_3; + } + } else if (trigger_data->fps == -1) { + //Frame duration based on epoch-sof calculation + if (link->retry_threshold) { + /* Increase threshold value by dividing frame + * duration with 2 + */ + link->retry_threshold -= 1; + threshold = frame_duration / THRESHOLD_FACTOR_2; + } else { + /* Normal threshold calculation by dividing frame + * duration with 3 + */ + threshold = frame_duration / THRESHOLD_FACTOR_3; + } + } else { + link->fps = trigger_data->fps; + frame_duration = + trigger_data->fps * MILLI_SECOND_CONVERSION_FACTOR; + if (link->retry_threshold) { + /* Increase threshold value by dividing frame + * duration with 2 + */ + link->retry_threshold -= 1; + threshold = frame_duration / THRESHOLD_FACTOR_2; + } else { + /* Normal threshold calculation by dividing frame + * duration with 3 + */ + threshold = frame_duration / THRESHOLD_FACTOR_3; + } + } + if (curr_sync_time > threshold) { struct cam_req_mgr_dump_link_data dump_info; - CAM_DBG(CAM_CRM, - "Master %x and slave %x are not in same time frame time diff %lld threshold %lld", + + link->retry_threshold = 3; + CAM_INFO_RATE_LIMIT(CAM_CRM, + "Master %x and slave %x sof diff is more than threshold: time diff %lld threshold %lld fps %d bootime %lld", link->link_hdl, link->sync_link[i]->link_hdl, - curr_sync_time/1000000, - threshold/1000000); + curr_sync_time / MILLI_SECOND_CONVERSION_FACTOR, + threshold / MILLI_SECOND_CONVERSION_FACTOR, + trigger_data->fps, + (curr_boot_timestamp / + MILLI_SECOND_CONVERSION_FACTOR)); dump_info.m_link = link; dump_info.s_link = link->sync_link[i]; @@ -3780,7 +3886,7 @@ static int cam_req_mgr_cb_notify_trigger( struct cam_req_mgr_dump_link_data dump_info; - CAM_DBG(CAM_CRM, + CAM_INFO_RATE_LIMIT(CAM_CRM, "Req diff %lld Master link %x req %lld slave link %x req %lld", req_diff, link->link_hdl, @@ -4003,7 +4109,7 @@ slave: tmp_slot->real_sync_mode != CAM_REQ_MGR_SYNC_MODE_SYNC)) { CAM_DBG(CAM_CRM, - "In sync mode req %lld tmp mode % real mode %d sync mode %d link %x ", + "In sync mode req %lld tmp mode %d real mode %d sync mode %d link %x ", slot->req_id, tmp_slot->sync_mode, tmp_slot->real_sync_mode, slot->sync_mode, link->link_hdl); @@ -4062,6 +4168,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { .add_req = cam_req_mgr_cb_add_req, .notify_timer = cam_req_mgr_cb_notify_timer, .notify_stop = cam_req_mgr_cb_notify_stop, + .notify_rup = cam_req_mgr_cb_notify_rup, }; /** @@ -4770,43 +4877,47 @@ static void __cam_req_mgr_set_master_link( int32_t num_of_links) { int i = 0, j = 0, k = 0; - int idx = -1; - - idx = find_first_bit(g_crm_core_dev->bitmap, - MAXIMUM_LINKS_PER_SESSION); + int master_link_idx = 0; + int max_isp = -1, min_isp = MAX_LINKS_PER_SESSION + 1; + int min_isp_link_idx = 0, max_isp_link_idx = 0; + struct cam_req_mgr_connected_device *dev = NULL; for (i = 0; i < num_of_links; i++) { - - CAM_DBG(CAM_CRM, "idx %d, link%d 0x%x active seq %d", - idx, i, link[i]->link_hdl, - link[i]->activate_seq); - - if (link[i]->activate_seq == idx) { - - link[i]->is_master = true; - CAM_DBG(CAM_CRM, "Master link 0x%x num of links %d ", - link[i]->link_hdl, num_of_links); - - for (j = 0, k = 0; j < num_of_links; j++) { - if (link[i]->link_hdl != - link[j]->link_hdl) { - - link[i]->sync_link[k] = link[j]; - link[i]->num_sync_link++; - - link[j]->sync_link[0] = link[i]; - link[j]->num_sync_link = 1; - link[j]->is_master = false; - - k++; - } - } + for (j = 0; j < link[i]->num_devs; j++) { + dev = &link[i]->l_dev[j]; + if (strcmp("cam-isp", dev->dev_info.name) == 0) + link[i]->num_isp_dev++; } + if (max_isp < link[i]->num_isp_dev) { + max_isp = link[i]->num_isp_dev; + max_isp_link_idx = i; + } + if (min_isp > link[i]->num_isp_dev) { + min_isp = link[i]->num_isp_dev; + min_isp_link_idx = i; + } + + if (link[master_link_idx]->activate_seq > link[i]->activate_seq) + master_link_idx = i; + } + + if (max_isp != min_isp) + master_link_idx = min_isp_link_idx; + + link[master_link_idx]->is_master = true; + CAM_DBG(CAM_CRM, "Master link %x ", link[master_link_idx]->link_hdl); + + for (i = 0; i < num_of_links; i++) { + if (i != master_link_idx) { + link[i]->is_master = false; + link[i]->sync_link[0] = link[master_link_idx]; + link[i]->num_sync_link = 1; + link[master_link_idx]->sync_link[k++] = link[i]; + link[master_link_idx]->num_sync_link++; + } link[i]->initial_skip = g_crm_core_dev->max_delay - link[i]->max_delay; - CAM_DBG(CAM_CRM, "link %x initial skip %d", - link[i]->link_hdl, link[i]->initial_skip); } } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 9808cb0b31..13ac9b5d87 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -394,6 +394,9 @@ struct cam_req_mgr_connected_device { * @frame_id : current frame id * @sync_frame_id : current frame id of sync link * @bubble_skip : req to skip on bubble + * @num_isp_dev : number of isp dev in a link + * @retry_threshold : number of times to retry apply on increased threshold + * @fps : current frame rate */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -439,6 +442,9 @@ struct cam_req_mgr_core_link { uint64_t sync_frame_id; int32_t bubble_skip; bool skip_sync_apply; + uint32_t num_isp_dev; + uint32_t retry_threshold; + uint32_t fps; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index e8e4f941a3..4be12ccf63 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -12,6 +12,7 @@ #include "cam_req_mgr_util.h" struct cam_req_mgr_trigger_notify; +struct cam_req_mgr_notify_rup; struct cam_req_mgr_error_notify; struct cam_req_mgr_add_request; struct cam_req_mgr_timer_notify; @@ -23,19 +24,21 @@ struct cam_req_mgr_flush_request; struct cam_req_mgr_link_evt_data; struct cam_req_mgr_dump_info; struct cam_req_mgr_request_change_state; +struct cam_req_mgr_signal_info; /* Request Manager -- camera device driver interface */ /** * @brief: camera kernel drivers to cam req mgr communication * * @cam_req_mgr_notify_trigger: for device which generates trigger to inform CRM + * @cam_req_mgr_notify_rup : for device which generates reg update trigger to inform CRM * @cam_req_mgr_notify_err : device use this to inform about different errors * @cam_req_mgr_add_req : to info CRM about new rqeuest received from * userspace * @cam_req_mgr_notify_timer : start the timer */ -typedef int (*cam_req_mgr_notify_trigger)( - struct cam_req_mgr_trigger_notify *); +typedef int (*cam_req_mgr_notify_trigger)(struct cam_req_mgr_trigger_notify *); +typedef int (*cam_req_mgr_notify_rup)(struct cam_req_mgr_notify_rup *); typedef bool (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); @@ -62,8 +65,8 @@ typedef int (*cam_req_mgr_notify_frame_skip)( typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *); typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); typedef int (*cam_req_mgr_dump_req)(struct cam_req_mgr_dump_info *); -typedef int (*cam_req_mgr_change_state)( - struct cam_req_mgr_request_change_state *); +typedef int (*cam_req_mgr_change_state)(struct cam_req_mgr_request_change_state *); +typedef int (*cam_req_mgr_signal_buf_done)(struct cam_req_mgr_signal_info *); /** * @brief : cam_req_mgr_crm_cb - func table @@ -73,6 +76,7 @@ typedef int (*cam_req_mgr_change_state)( * @add_req : payload to inform which device and what request is received * @notify_timer : payload for timer start event * @notify_stop : payload to inform stop event + * @notify_rup : payload to inform reg update ack */ struct cam_req_mgr_crm_cb { cam_req_mgr_notify_trigger notify_trigger; @@ -80,6 +84,7 @@ struct cam_req_mgr_crm_cb { cam_req_mgr_add_req add_req; cam_req_mgr_notify_timer notify_timer; cam_req_mgr_notify_stop notify_stop; + cam_req_mgr_notify_rup notify_rup; }; /** @@ -103,6 +108,7 @@ struct cam_req_mgr_kmd_ops { cam_req_mgr_process_evt process_evt; cam_req_mgr_dump_req dump_req; cam_req_mgr_change_state change_state; + cam_req_mgr_signal_buf_done signal_buf_done; }; /** @@ -215,6 +221,17 @@ enum cam_req_mgr_link_evt_type { CAM_REQ_MGR_LINK_EVT_MAX, }; +/** + * enum cam_req_mgr_buf_done_state + * @INIT_BUF_DONE : Initial buf done state of a request + * @SIGNAL_SYNC_BUF_DONE : Ready to signal buf done of a request if in sync mode + * @SIGNAL_NON_SYNC_BUF_DONE : Ready to signal buf done of a request if in non sync mode + */ +enum cam_req_mgr_buf_done_state { + INIT_BUF_DONE, + SIGNAL_SYNC_BUF_DONE, +}; + /** * struct cam_req_mgr_trigger_notify * @link_hdl : link identifier @@ -226,6 +243,7 @@ enum cam_req_mgr_link_evt_type { * @sof_boottime : Captured boot time stamp value at sof hw event * @req_id : req id which returned buf_done * @trigger_id: ID to differentiate between the trigger devices + * @fps : Current fps value */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; @@ -236,6 +254,19 @@ struct cam_req_mgr_trigger_notify { uint64_t sof_boottime; uint64_t req_id; int32_t trigger_id; + uint32_t fps; +}; + +/** + * struct cam_req_mgr_notify_rup + * @link_hdl : link identifier + * @req_id : req id which returned reg update ack + * @state : buf done ready state of the request + */ +struct cam_req_mgr_notify_rup { + int32_t link_hdl; + uint64_t req_id; + int32_t state; }; /** @@ -353,6 +384,7 @@ struct cam_req_mgr_core_dev_link_setup { * @report_if_bubble : report to crm if failure in applying * @trigger_point : the trigger point of this apply * @re_apply : to skip re_apply for buf_done request + * @is_sync_mode : if request need to be apply in sync with other link * */ struct cam_req_mgr_apply_request { @@ -362,6 +394,7 @@ struct cam_req_mgr_apply_request { int32_t report_if_bubble; uint32_t trigger_point; bool re_apply; + bool is_sync_mode; }; /** @@ -456,4 +489,19 @@ struct cam_req_mgr_request_change_state { uint64_t req_id; }; +/** + * struct cam_req_mgr_signal_info + * @link_hdl : link identifier + * @dev_hdl : device handle or identifier + * req_id : request id to be set for buf done ready + * state : Buf done ready state of a request + * + */ +struct cam_req_mgr_signal_info { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + int32_t state; +}; + #endif diff --git a/include/uapi/camera/media/cam_isp.h b/include/uapi/camera/media/cam_isp.h index 5716aea8bf..42a5071b3b 100644 --- a/include/uapi/camera/media/cam_isp.h +++ b/include/uapi/camera/media/cam_isp.h @@ -122,6 +122,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_TPG_CORE_CONFIG 14 #define CAM_ISP_GENERIC_BLOB_TYPE_DYNAMIC_MODE_SWITCH 15 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_LIMITER_CFG 16 +#define CAM_ISP_GENERIC_BLOB_TYPE_FPS_CONFIG 17 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG 21 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CORE_CONFIG 22 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG 23 @@ -822,6 +823,18 @@ struct cam_isp_acquire_hw_info { __u64 data; }; +/** + * struct cam_fps_config - FPS info per request + * + * @fps : Fps value + * @reserved: : Reserved field for alignment + * + */ +struct cam_fps_config { + __u32 fps; + __u32 reserved_params[3]; +} __attribute__((packed)); + /** * struct cam_isp_vfe_wm_config - VFE write master config per port *