Browse Source

msm: camera: isp: Add support for QCFA CSID binning

Add support to configure CSID binning for QCFA.

Change-Id: I9e2673d89f521a4b4fddc41ad1217ffe229d8b01
Signed-off-by: Tejas Prajapati <[email protected]>
Signed-off-by: Trishansh Bhardwaj <[email protected]>
Signed-off-by: Jigarkumar Zala <[email protected]>
Jigarkumar Zala 6 years ago
parent
commit
f458d1d231

+ 27 - 0
drivers/cam_cpas/cam_cpas_intf.c

@@ -12,9 +12,11 @@
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-subdev.h>
 #include <cam_cpas.h>
 #include <cam_cpas.h>
 #include <cam_req_mgr.h>
 #include <cam_req_mgr.h>
+#include <dt-bindings/msm/msm-camera.h>
 
 
 #include "cam_subdev.h"
 #include "cam_subdev.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_hw_intf.h"
+#include "cam_cpas_soc.h"
 
 
 #define CAM_CPAS_DEV_NAME    "cam-cpas"
 #define CAM_CPAS_DEV_NAME    "cam-cpas"
 #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
 #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
@@ -104,6 +106,31 @@ const char *cam_cpas_axi_util_trans_type_to_string(
 }
 }
 EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
 EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
 
 
+int cam_cpas_is_feature_supported(uint32_t flag)
+{
+	struct cam_hw_info *cpas_hw = NULL;
+	struct cam_cpas_private_soc *soc_private = NULL;
+	uint32_t feature_mask;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+
+	cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
+	soc_private =
+		(struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
+	feature_mask = soc_private->feature_mask;
+
+	if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
+		CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
+		return -EINVAL;
+	}
+
+	return feature_mask & flag ? 1 : 0;
+}
+EXPORT_SYMBOL(cam_cpas_is_feature_supported);
+
 int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
 int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
 {
 {
 	struct cam_hw_info *cpas_hw = NULL;
 	struct cam_hw_info *cpas_hw = NULL;

+ 42 - 0
drivers/cam_cpas/cam_cpas_soc.c

@@ -349,6 +349,45 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
 	return 0;
 	return 0;
 }
 }
 
 
+
+int cam_cpas_get_hw_features(struct platform_device *pdev,
+	struct cam_cpas_private_soc *soc_private)
+{
+	struct device_node *of_node;
+	void *fuse;
+	uint32_t fuse_addr, fuse_bit;
+	uint32_t fuse_val = 0, feature_bit_pos;
+	int count = 0, i = 0;
+
+	of_node = pdev->dev.of_node;
+	count = of_property_count_u32_elems(of_node, "cam_hw_fuse");
+
+	for (i = 0; (i + 3) <= count; i = i + 3) {
+		of_property_read_u32_index(of_node, "cam_hw_fuse", i,
+				&feature_bit_pos);
+		of_property_read_u32_index(of_node, "cam_hw_fuse", i + 1,
+				&fuse_addr);
+		of_property_read_u32_index(of_node, "cam_hw_fuse", i + 2,
+				&fuse_bit);
+		CAM_INFO(CAM_CPAS, "feature_bit 0x%x addr 0x%x, bit %d",
+				feature_bit_pos, fuse_addr, fuse_bit);
+
+		fuse = ioremap(fuse_addr, 4);
+		if (fuse) {
+			fuse_val = cam_io_r(fuse);
+			if (fuse_val & BIT(fuse_bit))
+				soc_private->feature_mask |= feature_bit_pos;
+			else
+				soc_private->feature_mask &= ~feature_bit_pos;
+		}
+		CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x",
+				fuse, fuse_val, soc_private->feature_mask);
+
+	}
+
+	return 0;
+}
+
 int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 	struct platform_device *pdev, struct cam_cpas_private_soc *soc_private)
 	struct platform_device *pdev, struct cam_cpas_private_soc *soc_private)
 {
 {
@@ -363,6 +402,7 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 	}
 	}
 
 
 	of_node = pdev->dev.of_node;
 	of_node = pdev->dev.of_node;
+	soc_private->feature_mask = 0xFFFFFFFF;
 
 
 	rc = of_property_read_string(of_node, "arch-compat",
 	rc = of_property_read_string(of_node, "arch-compat",
 		&soc_private->arch_compat);
 		&soc_private->arch_compat);
@@ -372,6 +412,8 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
 		return rc;
 		return rc;
 	}
 	}
 
 
+	cam_cpas_get_hw_features(pdev, soc_private);
+
 	soc_private->camnoc_axi_min_ib_bw = 0;
 	soc_private->camnoc_axi_min_ib_bw = 0;
 	rc = of_property_read_u64(of_node,
 	rc = of_property_read_u64(of_node,
 		"camnoc-axi-min-ib-bw",
 		"camnoc-axi-min-ib-bw",

+ 2 - 0
drivers/cam_cpas/cam_cpas_soc.h

@@ -87,6 +87,7 @@ struct cam_cpas_tree_node {
  * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating
  * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating
  *      camnoc axi clock
  *      camnoc axi clock
  * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target
  * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target
+ * @feature_mask: feature mask value for hw supported features
  *
  *
  */
  */
 struct cam_cpas_private_soc {
 struct cam_cpas_private_soc {
@@ -103,6 +104,7 @@ struct cam_cpas_private_soc {
 	uint32_t camnoc_bus_width;
 	uint32_t camnoc_bus_width;
 	uint32_t camnoc_axi_clk_bw_margin;
 	uint32_t camnoc_axi_clk_bw_margin;
 	uint64_t camnoc_axi_min_ib_bw;
 	uint64_t camnoc_axi_min_ib_bw;
+	uint32_t feature_mask;
 };
 };
 
 
 void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private);
 void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private);

+ 13 - 0
drivers/cam_cpas/include/cam_cpas_api.h

@@ -525,6 +525,19 @@ int cam_cpas_get_hw_info(
 int cam_cpas_get_cpas_hw_version(
 int cam_cpas_get_cpas_hw_version(
 	uint32_t				 *hw_version);
 	uint32_t				 *hw_version);
 
 
+/**
+ * cam_cpas_is_feature_supported()
+ *
+ * @brief: API to get camera features
+ *
+ * @flag  : Camera hw features to check
+ *
+ * @return 1 if feature is supported
+ *
+ */
+int cam_cpas_is_feature_supported(
+	uint32_t flag);
+
 /**
 /**
  * cam_cpas_axi_util_path_type_to_string()
  * cam_cpas_axi_util_path_type_to_string()
  *
  *

+ 68 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -4236,6 +4236,54 @@ static int cam_isp_blob_csid_clock_update(
 	return rc;
 	return rc;
 }
 }
 
 
+static int cam_isp_blob_csid_qcfa_update(
+	uint32_t                               blob_type,
+	struct cam_isp_generic_blob_info      *blob_info,
+	struct cam_isp_csid_qcfa_config       *qcfa_config,
+	struct cam_hw_prepare_update_args     *prepare)
+{
+	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_ife_csid_qcfa_update_args   csid_qcfa_upd_args;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	ctx = prepare->ctxt_to_hw_map;
+
+	CAM_DBG(CAM_ISP,
+		"csid binning=%d", qcfa_config->csid_binning);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+
+			if (!hw_mgr_res->hw_res[i] ||
+				hw_mgr_res->res_id != CAM_IFE_PIX_PATH_RES_IPP)
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				csid_qcfa_upd_args.qcfa_binning =
+						qcfa_config->csid_binning;
+				CAM_DBG(CAM_ISP, "i= %d QCFA binning=%d\n",
+				i, csid_qcfa_upd_args.qcfa_binning);
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED,
+					&csid_qcfa_upd_args,
+					sizeof(
+					struct cam_ife_csid_qcfa_update_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "QCFA Update failed");
+			} else
+				CAM_ERR(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
 static int cam_isp_blob_core_cfg_update(
 static int cam_isp_blob_core_cfg_update(
 	uint32_t                               blob_type,
 	uint32_t                               blob_type,
 	struct cam_isp_generic_blob_info      *blob_info,
 	struct cam_isp_generic_blob_info      *blob_info,
@@ -4848,6 +4896,26 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			clock_config, prepare);
 			clock_config, prepare);
 		if (rc)
 		if (rc)
 			CAM_ERR(CAM_ISP, "Clock Update Failed");
 			CAM_ERR(CAM_ISP, "Clock Update Failed");
+	}
+		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG: {
+		struct cam_isp_csid_qcfa_config *qcfa_config;
+
+		if (blob_size < sizeof(struct cam_isp_csid_qcfa_config)) {
+			CAM_ERR(CAM_ISP,
+				"Invalid qcfa blob size %u expected %u",
+				blob_size,
+				sizeof(struct cam_isp_csid_qcfa_config));
+			return -EINVAL;
+		}
+
+		qcfa_config = (struct cam_isp_csid_qcfa_config *)blob_data;
+
+		rc = cam_isp_blob_csid_qcfa_update(blob_type, blob_info,
+				qcfa_config, prepare);
+		if (rc)
+			CAM_ERR(CAM_ISP, "QCFA Update Failed rc: %d", rc);
+
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: {

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_IFE_CSID_175_200_H_
 #ifndef _CAM_IFE_CSID_175_200_H_
@@ -47,6 +47,7 @@ static struct cam_ife_csid_pxl_reg_offset
 	/* configurations */
 	/* configurations */
 	.pix_store_en_shift_val              = 7,
 	.pix_store_en_shift_val              = 7,
 	.early_eof_en_shift_val              = 29,
 	.early_eof_en_shift_val              = 29,
+	.quad_cfa_bin_en_shift_val           = 30,
 	.ccif_violation_en                   = 1,
 	.ccif_violation_en                   = 1,
 };
 };
 
 

+ 29 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c

@@ -8,6 +8,8 @@
 #include <uapi/media/cam_isp.h>
 #include <uapi/media/cam_isp.h>
 #include <uapi/media/cam_defs.h>
 #include <uapi/media/cam_defs.h>
 
 
+#include <dt-bindings/msm/msm-camera.h>
+
 #include "cam_ife_csid_core.h"
 #include "cam_ife_csid_core.h"
 #include "cam_isp_hw.h"
 #include "cam_isp_hw.h"
 #include "cam_soc_util.h"
 #include "cam_soc_util.h"
@@ -1611,6 +1613,10 @@ static int cam_ife_csid_init_config_pxl_path(
 			val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val);
 			val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val);
 	}
 	}
 
 
+	if (is_ipp && csid_hw->binning_supported &&
+		csid_hw->binning_enable)
+		val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val);
+
 	val |= (1 << pxl_reg->pix_store_en_shift_val);
 	val |= (1 << pxl_reg->pix_store_en_shift_val);
 	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
 	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
 		pxl_reg->csid_pxl_cfg0_addr);
 		pxl_reg->csid_pxl_cfg0_addr);
@@ -3124,6 +3130,23 @@ static int cam_ife_csid_set_csid_clock(
 	return 0;
 	return 0;
 }
 }
 
 
+static int cam_ife_csid_set_csid_qcfa(
+	struct cam_ife_csid_hw *csid_hw, void *cmd_args)
+{
+	struct cam_ife_csid_qcfa_update_args *qcfa_update = NULL;
+
+	if (!csid_hw)
+		return -EINVAL;
+
+	qcfa_update =
+		(struct cam_ife_csid_qcfa_update_args *)cmd_args;
+
+	csid_hw->binning_supported = qcfa_update->qcfa_binning;
+	CAM_DBG(CAM_ISP, "CSID QCFA binning %d", csid_hw->binning_supported);
+
+	return 0;
+}
+
 static int cam_ife_csid_process_cmd(void *hw_priv,
 static int cam_ife_csid_process_cmd(void *hw_priv,
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
 {
 {
@@ -3158,6 +3181,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
 	case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE:
 	case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE:
 		rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args);
 		rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args);
 		break;
 		break;
+	case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED:
+		rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args);
+		break;
 	default:
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);
 			csid_hw->hw_intf->hw_idx, cmd_type);
@@ -3601,6 +3627,9 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 		goto err;
 		goto err;
 	}
 	}
 
 
+	if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE) == 1)
+		ife_csid_hw->binning_enable = 1;
+
 	ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps;
 	ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps;
 	ife_csid_hw->hw_intf->hw_ops.init        = cam_ife_csid_init_hw;
 	ife_csid_hw->hw_intf->hw_ops.init        = cam_ife_csid_init_hw;
 	ife_csid_hw->hw_intf->hw_ops.deinit      = cam_ife_csid_deinit_hw;
 	ife_csid_hw->hw_intf->hw_ops.deinit      = cam_ife_csid_deinit_hw;

+ 4 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h

@@ -482,6 +482,8 @@ struct cam_ife_csid_path_cfg {
  * @irq_debug_cnt:            Counter to track sof irq's when above flag is set.
  * @irq_debug_cnt:            Counter to track sof irq's when above flag is set.
  * @error_irq_count           Error IRQ count, if continuous error irq comes
  * @error_irq_count           Error IRQ count, if continuous error irq comes
  *                            need to stop the CSID and mask interrupts.
  *                            need to stop the CSID and mask interrupts.
+ * @binning_enable            Flag is set if hardware supports QCFA binning
+ * @binning_supported         Flag is set if sensor supports QCFA binning
  *
  *
  */
  */
 struct cam_ife_csid_hw {
 struct cam_ife_csid_hw {
@@ -510,6 +512,8 @@ struct cam_ife_csid_hw {
 	uint32_t                         error_irq_count;
 	uint32_t                         error_irq_count;
 	uint32_t                         device_enabled;
 	uint32_t                         device_enabled;
 	spinlock_t                       lock_state;
 	spinlock_t                       lock_state;
+	uint32_t                         binning_enable;
+	uint32_t                         binning_supported;
 };
 };
 
 
 int cam_ife_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
 int cam_ife_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,

+ 9 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -222,5 +222,14 @@ struct cam_ife_csid_clock_update_args {
 	uint64_t                           clk_rate;
 	uint64_t                           clk_rate;
 };
 };
 
 
+/*
+ * struct cam_ife_csid_qcfa_update_args:
+ *
+ * @qcfa_binning:                QCFA binning supported
+ */
+struct cam_ife_csid_qcfa_update_args {
+	uint32_t                           qcfa_binning;
+};
+
 
 
 #endif /* _CAM_CSID_HW_INTF_H_ */
 #endif /* _CAM_CSID_HW_INTF_H_ */

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -100,6 +100,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_UBWC_UPDATE_V2,
 	CAM_ISP_HW_CMD_UBWC_UPDATE_V2,
 	CAM_ISP_HW_CMD_CORE_CONFIG,
 	CAM_ISP_HW_CMD_CORE_CONFIG,
 	CAM_ISP_HW_CMD_WM_CONFIG_UPDATE,
 	CAM_ISP_HW_CMD_WM_CONFIG_UPDATE,
+	CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED,
 	CAM_ISP_HW_CMD_MAX,
 	CAM_ISP_HW_CMD_MAX,
 };
 };