Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02af3487 authored by Karthik Anantha Ram's avatar Karthik Anantha Ram
Browse files

msm: camera: custom: Add support for SW sync & snapshot



Add support to handle SW sync & ZSLSnapshot. Add substate machine
and mechanism to handle the lifecycle of requests based on irqs
accordingly.

CRs-Fixed: 2524308
Change-Id: Ie5ba97d4ae1b38f4b44c2d3935d2882df59fcac6
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
parent f81a4600
Loading
Loading
Loading
Loading
+357 −31
Original line number Diff line number Diff line
@@ -27,6 +27,258 @@ static int __cam_custom_ctx_handle_irq_in_activated(
static int __cam_custom_ctx_start_dev_in_ready(
	struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd);

static int __cam_custom_ctx_apply_req_in_activated_state(
	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
	uint32_t next_state);

static int __cam_custom_ctx_apply_default_settings(
	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply);

static int __cam_custom_ctx_apply_req_in_activated(
	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply)
{
	int rc = 0;
	struct cam_custom_context *custom_ctx =
		(struct cam_custom_context *) ctx->ctx_priv;

	rc = __cam_custom_ctx_apply_req_in_activated_state(
		ctx, apply, CAM_CUSTOM_CTX_ACTIVATED_APPLIED);
	CAM_DBG(CAM_CUSTOM, "new substate %d", custom_ctx->substate_activated);

	if (rc)
		CAM_ERR(CAM_CUSTOM, "Apply failed in state %d rc %d",
			custom_ctx->substate_activated, rc);

	return rc;
}

static int __cam_custom_ctx_handle_error(
	struct cam_custom_context *custom_ctx, void *evt_data)
{
	/*
	 * Handle any HW error scenerios here, all the
	 * requests in all the lists can be signaled error.
	 * Notify UMD about this error if needed.
	 */

	return 0;
}

static int __cam_custom_ctx_reg_upd_in_sof(
	struct cam_custom_context *custom_ctx, void *evt_data)
{
	struct cam_ctx_request *req = NULL;
	struct cam_custom_dev_ctx_req *req_custom;
	struct cam_context *ctx = custom_ctx->base;

	custom_ctx->frame_id++;

	/*
	 * This is for the first update before streamon.
	 * The initial setting will cause the reg_upd in the
	 * first frame.
	 */
	if (!list_empty(&ctx->wait_req_list)) {
		req = list_first_entry(&ctx->wait_req_list,
			struct cam_ctx_request, list);
		list_del_init(&req->list);
		req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv;
		if (req_custom->num_fence_map_out == req_custom->num_acked) {
			list_add_tail(&req->list, &ctx->free_req_list);
		} else {
			list_add_tail(&req->list, &ctx->active_req_list);
			custom_ctx->active_req_cnt++;
			CAM_DBG(CAM_REQ,
				"move request %lld to active list(cnt = %d), ctx %u",
				req->request_id, custom_ctx->active_req_cnt,
				ctx->ctx_id);
		}
	}

	return 0;
}

static int __cam_custom_ctx_reg_upd_in_applied_state(
	struct cam_custom_context *custom_ctx, void *evt_data)
{
	struct cam_ctx_request         *req;
	struct cam_context             *ctx = custom_ctx->base;
	struct cam_custom_dev_ctx_req  *req_custom;

	custom_ctx->frame_id++;
	if (list_empty(&ctx->wait_req_list)) {
		CAM_ERR(CAM_CUSTOM,
				"Reg upd ack with no waiting request");
		goto end;
	}
	req = list_first_entry(&ctx->wait_req_list,
			struct cam_ctx_request, list);
	list_del_init(&req->list);

	req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv;
	if (req_custom->num_fence_map_out != 0) {
		list_add_tail(&req->list, &ctx->active_req_list);
		custom_ctx->active_req_cnt++;
		CAM_DBG(CAM_REQ,
			"move request %lld to active list(cnt = %d), ctx %u",
			req->request_id, custom_ctx->active_req_cnt,
			ctx->ctx_id);
	} else {
		/* no io config, so the request is completed. */
		list_add_tail(&req->list, &ctx->free_req_list);
		CAM_DBG(CAM_ISP,
			"move active request %lld to free list(cnt = %d), ctx %u",
			req->request_id, custom_ctx->active_req_cnt,
			ctx->ctx_id);
	}

	custom_ctx->substate_activated = CAM_CUSTOM_CTX_ACTIVATED_SOF;
	CAM_DBG(CAM_CUSTOM, "next substate %d", custom_ctx->substate_activated);

end:
	return 0;
}

static int __cam_custom_ctx_frame_done(
	struct cam_custom_context *custom_ctx, void *evt_data)
{
	int rc = 0, i, j;
	uint64_t frame_done_req_id;
	struct cam_ctx_request  *req;
	struct cam_custom_dev_ctx_req  *req_custom;
	struct cam_context *ctx = custom_ctx->base;
	struct cam_custom_hw_done_event_data *done_data =
		(struct cam_custom_hw_done_event_data *)evt_data;

	if (list_empty(&ctx->active_req_list)) {
		CAM_DBG(CAM_CUSTOM, "Frame done with no active request");
		return 0;
	}

	req = list_first_entry(&ctx->active_req_list,
			struct cam_ctx_request, list);
	req_custom = req->req_priv;

	for (i = 0; i < done_data->num_handles; i++) {
		for (j = 0; j < req_custom->num_fence_map_out; j++) {
			if (done_data->resource_handle[i] ==
				req_custom->fence_map_out[j].resource_handle)
				break;
		}

		if (j == req_custom->num_fence_map_out) {
			CAM_ERR(CAM_CUSTOM,
				"Can not find matching rsrc handle 0x%x!",
				done_data->resource_handle[i]);
			rc = -EINVAL;
			continue;
		}

		if (req_custom->fence_map_out[j].sync_id == -1) {
			CAM_WARN(CAM_CUSTOM,
				"Duplicate frame done for req %lld",
				req->request_id);
			continue;
		}

		rc = cam_sync_signal(req_custom->fence_map_out[j].sync_id,
				CAM_SYNC_STATE_SIGNALED_SUCCESS);
		if (rc)
			CAM_ERR(CAM_CUSTOM, "Sync failed with rc = %d", rc);

		req_custom->num_acked++;
		req_custom->fence_map_out[j].sync_id = -1;
	}

	if (req_custom->num_acked > req_custom->num_fence_map_out) {
		CAM_ERR(CAM_CUSTOM,
			"WARNING: req_id %lld num_acked %d > map_out %d, ctx %u",
			req->request_id, req_custom->num_acked,
			req_custom->num_fence_map_out, ctx->ctx_id);
	}

	if (req_custom->num_acked != req_custom->num_fence_map_out)
		return rc;

	custom_ctx->active_req_cnt--;
	frame_done_req_id = req->request_id;
	list_del_init(&req->list);
	list_add_tail(&req->list, &ctx->free_req_list);
	CAM_DBG(CAM_REQ,
		"Move active request %lld to free list(cnt = %d) [all fences done], ctx %u",
		frame_done_req_id, custom_ctx->active_req_cnt, ctx->ctx_id);

	return rc;
}

static struct cam_ctx_ops
	cam_custom_ctx_activated_state_machine
	[CAM_CUSTOM_CTX_ACTIVATED_MAX] = {
	/* SOF */
	{
		.ioctl_ops = {},
		.crm_ops = {
			.apply_req = __cam_custom_ctx_apply_req_in_activated,
			.apply_default =
				__cam_custom_ctx_apply_default_settings,
		},
		.irq_ops = NULL,
	},
	/* APPLIED */
	{
		.ioctl_ops = {},
		.crm_ops = {
			.apply_req = __cam_custom_ctx_apply_req_in_activated,
			.apply_default =
				__cam_custom_ctx_apply_default_settings,
		},
		.irq_ops = NULL,
	},
	/* HW ERROR */
	{
		.ioctl_ops = {},
		.crm_ops = {},
		.irq_ops = NULL,
	},
	/* HALT */
	{
		.ioctl_ops = {},
		.crm_ops = {},
		.irq_ops = NULL,
	},
};

static struct cam_custom_ctx_irq_ops
	cam_custom_ctx_activated_state_machine_irq
	[CAM_CUSTOM_CTX_ACTIVATED_MAX] = {
	/* SOF */
	{
		.irq_ops = {
			__cam_custom_ctx_handle_error,
			__cam_custom_ctx_reg_upd_in_sof,
			__cam_custom_ctx_frame_done,
		},
	},
	/* APPLIED */
	{
		.irq_ops = {
			__cam_custom_ctx_handle_error,
			__cam_custom_ctx_reg_upd_in_applied_state,
			__cam_custom_ctx_frame_done,
		},
	},
	/* HW ERROR */
	{
		.irq_ops = {
			NULL,
			NULL,
			NULL,
		},
	},
	/* HALT */
	{
	},
};

static int __cam_custom_ctx_enqueue_request_in_order(
	struct cam_context *ctx, struct cam_ctx_request *req)
@@ -484,7 +736,8 @@ static int __cam_custom_ctx_apply_default_settings(
}

static int __cam_custom_ctx_apply_req_in_activated_state(
	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply)
	struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
	uint32_t next_state)
{
	int rc = 0;
	struct cam_ctx_request          *req;
@@ -499,6 +752,9 @@ static int __cam_custom_ctx_apply_req_in_activated_state(
		goto end;
	}

	if (!list_empty(&ctx->wait_req_list))
		CAM_WARN(CAM_CUSTOM, "Apply invoked with a req in wait list");

	custom_ctx = (struct cam_custom_context *) ctx->ctx_priv;
	spin_lock_bh(&ctx->lock);
	req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
@@ -531,19 +787,10 @@ static int __cam_custom_ctx_apply_req_in_activated_state(
			"Can not apply the configuration");
	} else {
		spin_lock_bh(&ctx->lock);
		custom_ctx->substate_activated = next_state;
		list_del_init(&req->list);
		if (!req->num_out_map_entries) {
			list_add_tail(&req->list, &ctx->free_req_list);
		list_add_tail(&req->list, &ctx->wait_req_list);
		spin_unlock_bh(&ctx->lock);
		} else {
			list_add_tail(&req->list, &ctx->active_req_list);
			spin_unlock_bh(&ctx->lock);
			/*
			 * for test purposes only-this should be
			 * triggered based on irq
			 */
			 __cam_custom_ctx_handle_irq_in_activated(ctx, 0, NULL);
		}
	}

end:
@@ -610,6 +857,10 @@ static int __cam_custom_ctx_acquire_hw_v1(
		goto free_res;
	}

	ctx_custom->substate_machine_irq =
		cam_custom_ctx_activated_state_machine_irq;
	ctx_custom->substate_machine =
		cam_custom_ctx_activated_state_machine;
	ctx_custom->hw_ctx = param.ctxt_to_hw_map;
	ctx_custom->hw_acquired = true;
	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
@@ -808,7 +1059,9 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx,
	cfg.packet = packet;
	cfg.ctxt_to_hw_map = ctx_custom->hw_ctx;
	cfg.out_map_entries = req_custom->fence_map_out;
	cfg.max_out_map_entries = CAM_CUSTOM_DEV_CTX_RES_MAX;
	cfg.in_map_entries = req_custom->fence_map_in;
	cfg.max_in_map_entries = CAM_CUSTOM_DEV_CTX_RES_MAX;
	cfg.priv  = &req_custom->hw_update_data;
	cfg.pf_data = &(req->pf_data);

@@ -824,6 +1077,7 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx,
	req_custom->num_fence_map_out = cfg.num_out_map_entries;
	req_custom->num_fence_map_in = cfg.num_in_map_entries;
	req_custom->num_acked = 0;
	req_custom->hw_update_data.num_cfg = cfg.num_out_map_entries;

	for (i = 0; i < req_custom->num_fence_map_out; i++) {
		rc = cam_sync_get_obj_ref(req_custom->fence_map_out[i].sync_id);
@@ -1025,6 +1279,13 @@ static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx,
	else
		custom_start.start_only = false;

	ctx_custom->frame_id = 0;
	ctx_custom->active_req_cnt = 0;
	ctx_custom->substate_activated =
		(req_custom->num_fence_map_out) ?
		CAM_CUSTOM_CTX_ACTIVATED_APPLIED :
		CAM_CUSTOM_CTX_ACTIVATED_SOF;

	ctx->state = CAM_CTX_ACTIVATED;
	rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
		&custom_start);
@@ -1040,10 +1301,7 @@ static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx,

	spin_lock_bh(&ctx->lock);
	list_del_init(&req->list);
	if (req_custom->num_fence_map_out)
		list_add_tail(&req->list, &ctx->active_req_list);
	else
		list_add_tail(&req->list, &ctx->free_req_list);
	list_add_tail(&req->list, &ctx->wait_req_list);
	spin_unlock_bh(&ctx->lock);

end:
@@ -1103,20 +1361,28 @@ static int __cam_custom_ctx_process_evt(struct cam_context *ctx,
static int __cam_custom_ctx_handle_irq_in_activated(void *context,
	uint32_t evt_id, void *evt_data)
{
	int rc;
	struct cam_context *ctx =
		(struct cam_context *)context;
	int rc = 0;
	struct cam_custom_ctx_irq_ops *custom_irq_ops = NULL;
	struct cam_context *ctx = (struct cam_context *)context;
	struct cam_custom_context *ctx_custom =
		(struct cam_custom_context *)ctx->ctx_priv;

	CAM_DBG(CAM_CUSTOM, "Enter %d", ctx->ctx_id);
	spin_lock(&ctx->lock);
	CAM_DBG(CAM_CUSTOM, "Enter: State %d, Substate %d, evt id %d",
		 ctx->state, ctx_custom->substate_activated, evt_id);
	custom_irq_ops = &ctx_custom->substate_machine_irq[
				ctx_custom->substate_activated];
	if (custom_irq_ops->irq_ops[evt_id])
		rc = custom_irq_ops->irq_ops[evt_id](ctx_custom,
			evt_data);
	else
		CAM_DBG(CAM_CUSTOM, "No handle function for substate %d",
			ctx_custom->substate_activated);

	/*
	 * handle based on different irq's currently
	 * triggering only buf done if there are fences
	 */
	rc = cam_context_buf_done_from_hw(ctx, evt_data, 0);
	if (rc)
		CAM_ERR(CAM_CUSTOM, "Failed in buf done, rc=%d", rc);
	CAM_DBG(CAM_CUSTOM, "Exit: State %d Substate %d",
		 ctx->state, ctx_custom->substate_activated);

	spin_unlock(&ctx->lock);
	return rc;
}

@@ -1141,6 +1407,67 @@ static int __cam_custom_ctx_acquire_hw_in_acquired(
	return rc;
}

static int __cam_custom_ctx_apply_req(struct cam_context *ctx,
	struct cam_req_mgr_apply_request *apply)
{
	int rc = 0;
	struct cam_ctx_ops *ctx_ops = NULL;
	struct cam_custom_context *custom_ctx =
		(struct cam_custom_context *) ctx->ctx_priv;

	CAM_DBG(CAM_CUSTOM,
		"Enter: apply req in Substate %d request _id:%lld",
		 custom_ctx->substate_activated, apply->request_id);

	ctx_ops = &custom_ctx->substate_machine[
		custom_ctx->substate_activated];
	if (ctx_ops->crm_ops.apply_req) {
		rc = ctx_ops->crm_ops.apply_req(ctx, apply);
	} else {
		CAM_WARN_RATE_LIMIT(CAM_CUSTOM,
			"No handle function in activated substate %d",
			custom_ctx->substate_activated);
		rc = -EFAULT;
	}

	if (rc)
		CAM_WARN_RATE_LIMIT(CAM_CUSTOM,
			"Apply failed in active substate %d rc %d",
			custom_ctx->substate_activated, rc);
	return rc;
}

static int __cam_custom_ctx_apply_default_req(
	struct cam_context *ctx,
	struct cam_req_mgr_apply_request *apply)
{
	int rc = 0;
	struct cam_ctx_ops *ctx_ops = NULL;
	struct cam_custom_context *custom_ctx =
		(struct cam_custom_context *) ctx->ctx_priv;

	CAM_DBG(CAM_CUSTOM,
		"Enter: apply req in Substate %d request _id:%lld",
		 custom_ctx->substate_activated, apply->request_id);

	ctx_ops = &custom_ctx->substate_machine[
		custom_ctx->substate_activated];
	if (ctx_ops->crm_ops.apply_default) {
		rc = ctx_ops->crm_ops.apply_default(ctx, apply);
	} else {
		CAM_WARN_RATE_LIMIT(CAM_CUSTOM,
			"No handle function in activated substate %d",
			custom_ctx->substate_activated);
		rc = -EFAULT;
	}

	if (rc)
		CAM_WARN_RATE_LIMIT(CAM_CUSTOM,
			"Apply default failed in active substate %d rc %d",
			custom_ctx->substate_activated, rc);
	return rc;
}

/* top state machine */
static struct cam_ctx_ops
	cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = {
@@ -1219,10 +1546,9 @@ static struct cam_ctx_ops
		},
		.crm_ops = {
			.unlink = __cam_custom_ctx_unlink_in_activated,
			.apply_req =
				__cam_custom_ctx_apply_req_in_activated_state,
			.apply_req = __cam_custom_ctx_apply_req,
			.apply_default =
				__cam_custom_ctx_apply_default_settings,
				__cam_custom_ctx_apply_default_req,
			.flush_req = __cam_custom_ctx_flush_req_in_top_state,
			.process_evt = __cam_custom_ctx_process_evt,
		},
+44 −12
Original line number Diff line number Diff line
@@ -19,13 +19,39 @@
 * output port resource. The current maximum resource number
 * is 2.
 */
#define CAM_CUSTOM_DEV_CTX_RES_MAX                     2
#define CAM_CUSTOM_DEV_CTX_RES_MAX                     1

#define CAM_CUSTOM_CTX_CFG_MAX                         8

/* forward declaration */
struct cam_custom_context;

/* cam custom context irq handling function type */
typedef int (*cam_custom_hw_event_cb_func)(
	struct cam_custom_context *custom_ctx, void *evt_data);

/**
 * enum cam_custom_ctx_activated_substate - sub states for activated
 *
 */
enum cam_custom_ctx_activated_substate {
	CAM_CUSTOM_CTX_ACTIVATED_SOF,
	CAM_CUSTOM_CTX_ACTIVATED_APPLIED,
	CAM_CUSTOM_CTX_ACTIVATED_HW_ERROR,
	CAM_CUSTOM_CTX_ACTIVATED_HALT,
	CAM_CUSTOM_CTX_ACTIVATED_MAX,
};

/**
 * struct cam_custom_ctx_irq_ops - Function table for handling IRQ callbacks
 *
 * @irq_ops:               Array of handle function pointers.
 *
 */
struct cam_custom_ctx_irq_ops {
	cam_custom_hw_event_cb_func         irq_ops[CAM_CUSTOM_HW_EVENT_MAX];
};

/**
 * struct cam_custom_dev_ctx_req - Custom context request object
 *
@@ -69,6 +95,9 @@ struct cam_custom_dev_ctx_req {
 * @active_req_cnt: Counter for the active request
 * @frame_id: Frame id tracking for the custom context
 * @hw_acquired: Flag to indicate if HW is acquired for this context
 * @substate_actiavted: Current substate for the activated state.
 * @substate_machine: Custom substate machine for external interface
 * @substate_machine_irq: Custom substate machine for irq handling
 * @req_base: common request structure
 * @req_custom: custom request structure
 *
@@ -83,6 +112,9 @@ struct cam_custom_context {
	uint32_t                       active_req_cnt;
	int64_t                        frame_id;
	bool                           hw_acquired;
	uint32_t                       substate_activated;
	struct cam_ctx_ops            *substate_machine;
	struct cam_custom_ctx_irq_ops *substate_machine_irq;
	struct cam_ctx_request         req_base[CAM_CTX_REQ_MAX];
	struct cam_custom_dev_ctx_req  req_custom[CAM_CTX_REQ_MAX];
};
+1 −3
Original line number Diff line number Diff line
@@ -283,8 +283,6 @@ irqreturn_t cam_custom_hw_sub_mod_irq(int irq_num, void *data)
			core_info->device_hw_info->irq_clear);

	spin_lock(&custom_dev->hw_lock);
	cb_args.irq_status = irq_status;
	cb_args.req_info = core_info->curr_req;
	core_info->curr_req = NULL;
	if (core_info->irq_cb.custom_hw_mgr_cb)
		core_info->irq_cb.custom_hw_mgr_cb(
@@ -315,7 +313,7 @@ int cam_custom_hw_sub_mod_process_cmd(void *hw_priv, uint32_t cmd_type,
	switch (cmd_type) {
	case CAM_CUSTOM_SET_IRQ_CB: {
		struct cam_custom_sub_mod_set_irq_cb *irq_cb = cmd_args;

		/* This can be deprecated */
		CAM_DBG(CAM_CUSTOM, "Setting irq cb");
		spin_lock_irqsave(&hw->hw_lock, flag);
		core_info->irq_cb.custom_hw_mgr_cb = irq_cb->custom_hw_mgr_cb;
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ enum cam_custom_hw_resource_type {
struct cam_custom_sub_mod_acq {
	enum cam_custom_hw_resource_type   rsrc_type;
	int32_t                            acq;
	cam_hw_mgr_event_cb_func           event_cb;
	void                              *priv;
	struct cam_custom_resource_node   *rsrc_node;
};

+179 −58

File changed.

Preview size limit exceeded, changes collapsed.

Loading