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 <tpraja@codeaurora.org>
Signed-off-by: Trishansh Bhardwaj <tbhardwa@codeaurora.org>
Signed-off-by: Jigarkumar Zala <jzala@codeaurora.org>
This commit is contained in:
Jigarkumar Zala 2019-08-06 10:46:50 -07:00 committed by Gerrit - the friendly Code Review server
parent a89607a875
commit f458d1d231
10 changed files with 197 additions and 1 deletions

View File

@ -12,9 +12,11 @@
#include <media/v4l2-subdev.h>
#include <cam_cpas.h>
#include <cam_req_mgr.h>
#include <dt-bindings/msm/msm-camera.h>
#include "cam_subdev.h"
#include "cam_cpas_hw_intf.h"
#include "cam_cpas_soc.h"
#define CAM_CPAS_DEV_NAME "cam-cpas"
#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);
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)
{
struct cam_hw_info *cpas_hw = NULL;

View File

@ -349,6 +349,45 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
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,
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;
soc_private->feature_mask = 0xFFFFFFFF;
rc = of_property_read_string(of_node, "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;
}
cam_cpas_get_hw_features(pdev, soc_private);
soc_private->camnoc_axi_min_ib_bw = 0;
rc = of_property_read_u64(of_node,
"camnoc-axi-min-ib-bw",

View File

@ -87,6 +87,7 @@ struct cam_cpas_tree_node {
* @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating
* camnoc axi clock
* @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 {
@ -103,6 +104,7 @@ struct cam_cpas_private_soc {
uint32_t camnoc_bus_width;
uint32_t camnoc_axi_clk_bw_margin;
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);

View File

@ -525,6 +525,19 @@ int cam_cpas_get_hw_info(
int cam_cpas_get_cpas_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()
*

View File

@ -4236,6 +4236,54 @@ static int cam_isp_blob_csid_clock_update(
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(
uint32_t blob_type,
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);
if (rc)
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;
case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: {

View File

@ -1,6 +1,6 @@
/* 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_
@ -47,6 +47,7 @@ static struct cam_ife_csid_pxl_reg_offset
/* configurations */
.pix_store_en_shift_val = 7,
.early_eof_en_shift_val = 29,
.quad_cfa_bin_en_shift_val = 30,
.ccif_violation_en = 1,
};

View File

@ -8,6 +8,8 @@
#include <uapi/media/cam_isp.h>
#include <uapi/media/cam_defs.h>
#include <dt-bindings/msm/msm-camera.h>
#include "cam_ife_csid_core.h"
#include "cam_isp_hw.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);
}
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);
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
pxl_reg->csid_pxl_cfg0_addr);
@ -3124,6 +3130,23 @@ static int cam_ife_csid_set_csid_clock(
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,
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:
rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args);
break;
case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED:
rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args);
break;
default:
CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
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;
}
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.init = cam_ife_csid_init_hw;
ife_csid_hw->hw_intf->hw_ops.deinit = cam_ife_csid_deinit_hw;

View File

@ -482,6 +482,8 @@ struct cam_ife_csid_path_cfg {
* @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
* 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 {
@ -510,6 +512,8 @@ struct cam_ife_csid_hw {
uint32_t error_irq_count;
uint32_t device_enabled;
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,

View File

@ -222,5 +222,14 @@ struct cam_ife_csid_clock_update_args {
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_ */

View File

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