diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index e43d9f01ec2c..d1b32a0d916a 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -12,9 +12,11 @@ #include #include #include +#include #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; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index 6c34dd0687e6..c86753dd24d9 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/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; } + +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", diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index 7921cd4b956e..fea9c3c97593 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/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 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); diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 1126053e2b33..7c551dfcf8a5 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/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( 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() * 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 473a274eaf5c..faf2fb02e924 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 @@ -4234,6 +4234,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, @@ -4846,6 +4894,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: { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h index 7d47da31e4a8..869fd8cd61c9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h +++ b/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 */ /* - * 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, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 252c1a5aa36a..9503f204d410 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -8,6 +8,8 @@ #include #include +#include + #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; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 3e998858b596..d4a3a840d969 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/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. * @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, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index d8ba811c7ad5..e31cddc91b11 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/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; }; +/* + * 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_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 33254c1610ae..1e556137996d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/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_CORE_CONFIG, CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_MAX, };