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

Commit 24d06999 authored by Viswanadha Raju Thotakura's avatar Viswanadha Raju Thotakura
Browse files

msm: camera: Add support for IFE features



1. Add support to listen multiple virtual channels and data
   types from the input stream at CSID.
2. Update to user driver about the selected HW.
3. Add support for picking right HW when custom node is enabled.

Change-Id: I69f2b880892d3c23103ea5b5352303864932eb67
Signed-off-by: default avatarViswanadha Raju Thotakura <viswanad@codeaurora.org>
parent 8bde9d7a
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -83,6 +83,11 @@ struct cam_hw_done_event_data {
 * @num_acq:               Total number of acquire in the payload
 * @acquire_info:          Acquired resource array pointer
 * @ctxt_to_hw_map:        HW context (returned)
 * @acquired_hw_id:        Acquired hardware mask
 * @acquired_hw_path:      Acquired path mask for an input
 *                         if input splits into multiple paths,
 *                         its updated per hardware
 * valid_acquired_hw:      Valid num of acquired hardware
 *
 */
struct cam_hw_acquire_args {
@@ -92,6 +97,10 @@ struct cam_hw_acquire_args {
	uint32_t                     acquire_info_size;
	uintptr_t                    acquire_info;
	void                        *ctxt_to_hw_map;

	uint32_t    acquired_hw_id[CAM_MAX_ACQ_RES];
	uint32_t    acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT];
	uint32_t    valid_acquired_hw;
};

/**
+50 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/debugfs.h>
@@ -161,6 +161,45 @@ static int __cam_node_handle_acquire_hw_v1(struct cam_node *node,
	return 0;
}

static int __cam_node_handle_acquire_hw_v2(struct cam_node *node,
	struct cam_acquire_hw_cmd_v2 *acquire)
{
	int rc = 0;
	struct cam_context *ctx = NULL;

	if (!acquire)
		return -EINVAL;

	if (acquire->dev_handle <= 0) {
		CAM_ERR(CAM_CORE, "Invalid device handle for context");
		return -EINVAL;
	}

	if (acquire->session_handle <= 0) {
		CAM_ERR(CAM_CORE, "Invalid session handle for context");
		return -EINVAL;
	}

	ctx = (struct cam_context *)cam_get_device_priv(acquire->dev_handle);
	if (!ctx) {
		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
			acquire->dev_handle);
		return -EINVAL;
	}

	rc = cam_context_handle_acquire_hw(ctx, acquire);
	if (rc) {
		CAM_ERR(CAM_CORE, "Acquire device failed for node %s",
			node->name);
		return rc;
	}

	CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d",
		node->name, ctx->ctx_id);

	return 0;
}

static int __cam_node_handle_start_dev(struct cam_node *node,
	struct cam_start_stop_dev_cmd *start)
{
@@ -624,6 +663,8 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)

		if (api_version == 1) {
			acquire_size = sizeof(struct cam_acquire_hw_cmd_v1);
		} else if (api_version == 2) {
			acquire_size = sizeof(struct cam_acquire_hw_cmd_v2);
		} else {
			CAM_ERR(CAM_CORE, "Unsupported api version %d",
				api_version);
@@ -652,6 +693,14 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)
				goto acquire_kfree;
			}
			CAM_INFO(CAM_CORE, "Acquire HW successful");
		} else if (api_version == 2) {
			rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr);
			if (rc) {
				CAM_ERR(CAM_CORE,
					"acquire device failed(rc = %d)", rc);
				goto acquire_kfree;
			}
			CAM_INFO(CAM_CORE, "Acquire HW successful");
		}

		if (copy_to_user((void __user *)cmd->handle, acquire_ptr,
+144 −0
Original line number Diff line number Diff line
@@ -2948,6 +2948,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
		goto free_res;
	}

	memset(&param, 0, sizeof(param));
	param.context_data = ctx;
	param.event_cb = ctx->irq_cb_intf;
	param.num_acq = CAM_API_COMPAT_CONSTANT;
@@ -3022,6 +3023,147 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
	return rc;
}

static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
	void *args)
{
	int rc = 0, i, j;
	struct cam_acquire_hw_cmd_v2 *cmd =
		(struct cam_acquire_hw_cmd_v2 *)args;
	struct cam_hw_acquire_args       param;
	struct cam_hw_release_args       release;
	struct cam_isp_context          *ctx_isp =
		(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;
	struct cam_isp_acquire_hw_info  *acquire_hw_info = NULL;

	if (!ctx->hw_mgr_intf) {
		CAM_ERR(CAM_ISP, "HW interface is not ready");
		rc = -EFAULT;
		goto end;
	}

	CAM_DBG(CAM_ISP,
		"session_hdl 0x%x, hdl type %d, res %lld",
		cmd->session_handle, cmd->handle_type, cmd->resource_hdl);

	/* for now we only support user pointer */
	if (cmd->handle_type != 1)  {
		CAM_ERR(CAM_ISP, "Only user pointer is supported");
		rc = -EINVAL;
		goto end;
	}

	if (cmd->data_size < sizeof(*acquire_hw_info)) {
		CAM_ERR(CAM_ISP, "data_size is not a valid value");
		goto end;
	}

	acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL);
	if (!acquire_hw_info) {
		rc = -ENOMEM;
		goto end;
	}

	CAM_DBG(CAM_ISP, "start copy resources from user");

	if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl,
		cmd->data_size)) {
		rc = -EFAULT;
		goto free_res;
	}

	memset(&param, 0, sizeof(param));
	param.context_data = ctx;
	param.event_cb = ctx->irq_cb_intf;
	param.num_acq = CAM_API_COMPAT_CONSTANT;
	param.acquire_info_size = cmd->data_size;
	param.acquire_info = (uint64_t) acquire_hw_info;

	/* call HW manager to reserve the resource */
	rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv,
		&param);
	if (rc != 0) {
		CAM_ERR(CAM_ISP, "Acquire device failed");
		goto free_res;
	}

	/* Query the context has rdi only resource */
	hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map;
	hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
	isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE;
	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, "HW command failed");
		goto free_hw;
	}

	if (param.valid_acquired_hw) {
		for (i = 0; i < CAM_MAX_ACQ_RES; i++)
			cmd->hw_info.acquired_hw_id[i] =
				param.acquired_hw_id[i];

		for (i = 0; i < CAM_MAX_ACQ_RES; i++)
			for (j = 0; j < CAM_MAX_HW_SPLIT; j++)
				cmd->hw_info.acquired_hw_path[i][j] =
					param.acquired_hw_path[i][j];
	}
	cmd->hw_info.valid_acquired_hw =
		param.valid_acquired_hw;

	cmd->hw_info.valid_acquired_hw = param.valid_acquired_hw;

	if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) {
		/*
		 * this context has rdi only resource assign rdi only
		 * state machine
		 */
		CAM_DBG(CAM_ISP, "RDI only session Context");

		ctx_isp->substate_machine_irq =
			cam_isp_ctx_rdi_only_activated_state_machine_irq;
		ctx_isp->substate_machine =
			cam_isp_ctx_rdi_only_activated_state_machine;
		ctx_isp->rdi_only_context = true;
	} else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
		CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
		ctx_isp->substate_machine_irq =
			cam_isp_ctx_fs2_state_machine_irq;
		ctx_isp->substate_machine =
			cam_isp_ctx_fs2_state_machine;
	} else {
		CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
		ctx_isp->substate_machine_irq =
			cam_isp_ctx_activated_state_machine_irq;
		ctx_isp->substate_machine =
			cam_isp_ctx_activated_state_machine;
	}

	ctx_isp->hw_ctx = param.ctxt_to_hw_map;
	ctx_isp->hw_acquired = true;
	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;

	trace_cam_context_state("ISP", ctx);
	CAM_DBG(CAM_ISP,
		"Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u",
		ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id);
	kfree(acquire_hw_info);
	return rc;

free_hw:
	release.ctxt_to_hw_map = ctx_isp->hw_ctx;
	ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release);
	ctx_isp->hw_ctx = NULL;
	ctx_isp->hw_acquired = false;
free_res:
	kfree(acquire_hw_info);
end:
	return rc;
}


static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx,
	void *args)
{
@@ -3036,6 +3178,8 @@ static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx,
	api_version = *((uint32_t *)args);
	if (api_version == 1)
		rc = __cam_isp_ctx_acquire_hw_v1(ctx, args);
	else if (api_version == 2)
		rc = __cam_isp_ctx_acquire_hw_v2(ctx, args);
	else
		CAM_ERR(CAM_ISP, "Unsupported api version %d", api_version);

+482 −83

File changed.

Preview size limit exceeded, changes collapsed.

+133 −27
Original line number Diff line number Diff line
@@ -294,8 +294,41 @@ static int cam_ife_csid_get_format_ipp_ppp(
	return rc;
}

static int cam_ife_match_vc_dt_pair(int32_t *vc, uint32_t *dt,
	uint32_t num_valid_vc_dt, struct cam_ife_csid_cid_data *cid_data)
{
	uint32_t camera_hw_version;
	int rc = 0;

	rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
	if (rc) {
		CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc);
		return -EINVAL;
	}

	if (camera_hw_version != CAM_CPAS_TITAN_480_V100)
		num_valid_vc_dt = 1;

	switch (num_valid_vc_dt) {
	case 2:
		if (vc[1] != cid_data->vc1 ||
			dt[1] != cid_data->dt1)
			return -EINVAL;
	case 1:
		if (vc[0] != cid_data->vc ||
			dt[0] != cid_data->dt)
			return -EINVAL;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
	struct cam_isp_resource_node **res, int32_t vc, uint32_t dt)
	struct cam_isp_resource_node **res, int32_t *vc, uint32_t *dt,
	uint32_t num_valid_vc_dt)
{
	struct cam_ife_csid_cid_data    *cid_data;
	uint32_t  i = 0;
@@ -308,10 +341,11 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
			CAM_ISP_RESOURCE_STATE_RESERVED) {
			cid_data = (struct cam_ife_csid_cid_data *)
				csid_hw->cid_res[i].res_priv;
			if (cid_data->vc == vc && cid_data->dt == dt) {
			if (!cam_ife_match_vc_dt_pair(vc, dt,
				num_valid_vc_dt, cid_data)) {
				cid_data->cnt++;
				*res = &csid_hw->cid_res[i];
				CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated",
				CAM_DBG(CAM_ISP, "CSID:%d CID %d",
					csid_hw->hw_intf->hw_idx,
					csid_hw->cid_res[i].res_id);
				return 0;
@@ -324,8 +358,13 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
			cid_data = (struct cam_ife_csid_cid_data *)
				csid_hw->cid_res[i].res_priv;
			cid_data->vc  = vc;
			cid_data->dt  = dt;
			cid_data->vc  = vc[0];
			cid_data->dt  = dt[0];
			if (num_valid_vc_dt > 1) {
				cid_data->vc1  = vc[1];
				cid_data->dt1  = dt[1];
				cid_data->is_valid_vc1_dt1 = 1;
			}
			cid_data->cnt = 1;
			csid_hw->cid_res[i].res_state =
				CAM_ISP_RESOURCE_STATE_RESERVED;
@@ -585,9 +624,10 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw,
static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
	struct cam_csid_hw_reserve_resource_args  *cid_reserv)
{
	int rc = 0;
	int rc = 0, i;
	struct cam_ife_csid_cid_data       *cid_data;
	uint32_t camera_hw_version;
	uint32_t valid_vc_dt;

	CAM_DBG(CAM_ISP,
		"CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d",
@@ -595,8 +635,8 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
		cid_reserv->in_port->res_type,
		cid_reserv->in_port->lane_type,
		cid_reserv->in_port->lane_num,
		cid_reserv->in_port->dt,
		cid_reserv->in_port->vc);
		cid_reserv->in_port->dt[0],
		cid_reserv->in_port->vc[0]);

	if (cid_reserv->in_port->res_type >= CAM_ISP_IFE_IN_RES_MAX) {
		CAM_ERR(CAM_ISP, "CSID:%d  Invalid phy sel %d",
@@ -635,15 +675,20 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
		goto end;
	}

	valid_vc_dt = cid_reserv->in_port->num_valid_vc_dt;

	/* CSID  CSI2 v2.0 supports 31 vc  */
	if (cid_reserv->in_port->dt > 0x3f ||
		cid_reserv->in_port->vc > 0x1f) {
		CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d",
	for (i = 0; i < valid_vc_dt; i++) {
		if (cid_reserv->in_port->vc[i] > 0x1f ||
			cid_reserv->in_port->dt[i] > 0x3f) {
			CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d or dt: %d",
				csid_hw->hw_intf->hw_idx,
			cid_reserv->in_port->vc, cid_reserv->in_port->dt);
				cid_reserv->in_port->vc[i],
				cid_reserv->in_port->dt[i]);
			rc = -EINVAL;
			goto end;
		}
	}

	if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG && (
		(cid_reserv->in_port->format < CAM_FORMAT_MIPI_RAW_8 &&
@@ -684,6 +729,21 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
			goto end;
		}
		break;
	case CAM_CPAS_TITAN_480_V100:
		if (cid_reserv->in_port->cust_node == 1) {
			if (cid_reserv->in_port->usage_type == 1) {
				CAM_ERR(CAM_ISP, "Dual IFE is not supported");
				rc = -EINVAL;
				goto end;
			}
			if (csid_hw->hw_intf->hw_idx != 0) {
				CAM_DBG(CAM_ISP, "CSID%d not eligible",
					csid_hw->hw_intf->hw_idx);
				rc = -EINVAL;
				goto end;
			}
		}
		break;
	default:
		break;
	}
@@ -767,7 +827,8 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
	rc = cam_ife_csid_cid_get(csid_hw,
		&cid_reserv->node_res,
		cid_reserv->in_port->vc,
		cid_reserv->in_port->dt);
		cid_reserv->in_port->dt,
		cid_reserv->in_port->num_valid_vc_dt);
	if (rc) {
		CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d",
			csid_hw->hw_intf->hw_idx,
@@ -835,20 +896,27 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw,
static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw,
	struct cam_csid_hw_reserve_resource_args  *reserve)
{
	int rc = 0;
	int rc = 0, i;
	struct cam_ife_csid_path_cfg    *path_data;
	struct cam_isp_resource_node    *res;

	/* CSID  CSI2 v2.0 supports 31 vc */
	if (reserve->in_port->dt > 0x3f || reserve->in_port->vc > 0x1f ||
		(reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX)) {
		CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d mode:%d",
			 csid_hw->hw_intf->hw_idx,
			reserve->in_port->vc, reserve->in_port->dt,
	if (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX) {
		CAM_ERR(CAM_ISP, "CSID: %d Sync Mode: %d",
			reserve->sync_mode);
		return -EINVAL;
	}

	for (i = 0; i < reserve->in_port->num_valid_vc_dt; i++) {
		if (reserve->in_port->dt[i] > 0x3f ||
			reserve->in_port->vc[i] > 0x1f) {
			CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d",
				csid_hw->hw_intf->hw_idx,
				reserve->in_port->vc, reserve->in_port->dt);
			rc = -EINVAL;
			goto end;
		}
	}

	switch (reserve->res_id) {
	case CAM_IFE_PIX_PATH_RES_IPP:
@@ -980,8 +1048,13 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw,
		path_data->dt = CAM_IFE_CSID_TPG_DT_VAL;
		path_data->vc = CAM_IFE_CSID_TPG_VC_VAL;
	} else {
		path_data->dt = reserve->in_port->dt;
		path_data->vc = reserve->in_port->vc;
		path_data->dt = reserve->in_port->dt[0];
		path_data->vc = reserve->in_port->vc[0];
		if (reserve->in_port->num_valid_vc_dt) {
			path_data->dt1 = reserve->in_port->dt[1];
			path_data->vc1 = reserve->in_port->vc[1];
			path_data->is_valid_vc1_dt1 = 1;
		}
	}

	if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) {
@@ -1364,7 +1437,8 @@ static int cam_ife_csid_enable_csi2(
	/* rx cfg1*/
	val = (1 << csid_reg->csi2_reg->csi2_misr_enable_shift_val);
	/* if VC value is more than 3 than set full width of VC */
	if (cid_data->vc > 3)
	if (cid_data->vc > 3 || (cid_data->is_valid_vc1_dt1 &&
		cid_data->vc1 > 3))
		val |= (1 << csid_reg->csi2_reg->csi2_vc_mode_shift_val);

	/* enable packet ecc correction */
@@ -1496,6 +1570,7 @@ static int cam_ife_csid_init_config_pxl_path(
	const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL;
	bool                                      is_ipp;
	uint32_t decode_format = 0, plain_format = 0, val = 0;
	uint32_t camera_hw_version;

	path_data = (struct cam_ife_csid_path_cfg  *) res->res_priv;
	csid_reg = csid_hw->csid_info->csid_reg;
@@ -1540,6 +1615,21 @@ static int cam_ife_csid_init_config_pxl_path(
	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
		pxl_reg->csid_pxl_cfg0_addr);

	rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
	if (rc) {
		CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc);
		camera_hw_version = 0;
	}
	CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version);

	if (path_data->is_valid_vc1_dt1 &&
		camera_hw_version == CAM_CPAS_TITAN_480_V100) {
		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
			pxl_reg->csid_pxl_multi_vcdt_cfg0_addr);
		val |= ((path_data->vc1 << 2) |
			(path_data->dt1 << 7) | 1);
	}

	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
		pxl_reg->csid_pxl_cfg1_addr);

@@ -1907,6 +1997,7 @@ static int cam_ife_csid_init_config_rdi_path(
	struct cam_hw_soc_info                 *soc_info;
	uint32_t path_format = 0, plain_fmt = 0, val = 0, id;
	uint32_t format_measure_addr;
	uint32_t camera_hw_version;

	path_data = (struct cam_ife_csid_path_cfg   *) res->res_priv;
	csid_reg = csid_hw->csid_info->csid_reg;
@@ -1946,6 +2037,21 @@ static int cam_ife_csid_init_config_rdi_path(
	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
			csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr);

	rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
	if (rc) {
		CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc);
		camera_hw_version = 0;
	}
	CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version);

	if (path_data->is_valid_vc1_dt1 &&
		camera_hw_version == CAM_CPAS_TITAN_480_V100) {
		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
			csid_reg->rdi_reg[id]->csid_rdi_multi_vcdt_cfg0_addr);
		val |= ((path_data->vc1 << 2) |
			(path_data->dt1 << 7) | 1);
	}

	/* select the post irq sub sample strobe for time stamp capture */
	cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base +
			csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr);
Loading