Loading drivers/cam_cpas/cam_cpas_intf.c +34 −6 Original line number Diff line number Diff line Loading @@ -119,28 +119,56 @@ 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) bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map, uint32_t *fuse_val) { struct cam_hw_info *cpas_hw = NULL; struct cam_cpas_private_soc *soc_private = NULL; uint32_t feature_mask; bool supported = true; int32_t i; if (!CAM_CPAS_INTF_INITIALIZED()) { CAM_ERR(CAM_CPAS, "cpas intf not initialized"); return -ENODEV; return false; } 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 false; } for (i = 0; i < soc_private->num_feature_info; i++) if (soc_private->feature_info[i].feature == flag) break; if (i == soc_private->num_feature_info) { CAM_INFO(CAM_CPAS, "Feature not found, no of featues: %d", soc_private->num_feature_info); goto end; } if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE || (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_ENABLE)) { if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map) supported = soc_private->feature_info[i].enable; else supported = !soc_private->feature_info[i].enable; } else { if (!fuse_val) { CAM_ERR(CAM_CPAS, "Invalid arg fuse_val"); } else { *fuse_val = soc_private->feature_info[i].value; } } return feature_mask & flag ? 1 : 0; end: return supported; } EXPORT_SYMBOL(cam_cpas_is_feature_supported); Loading drivers/cam_cpas/cam_cpas_soc.c +125 −59 Original line number Diff line number Diff line Loading @@ -466,87 +466,155 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, return 0; } int cam_cpas_get_hw_fuse(struct platform_device *pdev, 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; memset(&soc_private->fuse_info, 0, sizeof(soc_private->fuse_info)); uint32_t fuse_addr, fuse_mask, fuse_shift; uint32_t val = 0, fuse_val = 0, feature; uint32_t enable_type = 0, hw_map = 0; int count = 0, i = 0, j = 0, num_feature = 0, num_fuse = 0; struct cam_cpas_feature_info *feature_info; of_node = pdev->dev.of_node; count = of_property_count_u32_elems(of_node, "cam_hw_fuse"); CAM_DBG(CAM_CPAS, "fuse info elements count %d", count); if (count <= 0) { CAM_INFO(CAM_CPAS, "no or invalid fuse enrties %d", count); return 0; } else if (count%3 != 0) { CAM_INFO(CAM_CPAS, "fuse entries should be multiple of 3 %d", CAM_INFO(CAM_CPAS, "No or invalid fuse entries count: %d", count); return -EINVAL; goto end; } else if (count%5 != 0) { CAM_INFO(CAM_CPAS, "fuse entries should be multiple of 5 %d", count); goto end; } for (i = 0; i < count; i = i + 3) { for (i = 0; (i + 5) <= count; i = i + 5) { of_property_read_u32_index(of_node, "cam_hw_fuse", i, &feature_bit_pos); &feature); 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_mask); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 3, &enable_type); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 4, &hw_map); val = ffs(fuse_mask); if (val == 0) { CAM_ERR(CAM_CPAS, "fuse_mask not valid 0x%x", fuse_mask); fuse_shift = 0; } else { fuse_shift = val - 1; } CAM_INFO(CAM_CPAS, "feature 0x%x addr 0x%x, mask 0x%x, shift 0x%x type 0x%x hw_map 0x%x", feature, fuse_addr, fuse_mask, fuse_shift, enable_type, hw_map); fuse = ioremap(fuse_addr, 4); if (fuse) { fuse_val = cam_io_r(fuse); soc_private->fuse_info.fuse_val[i].fuse_id = fuse_addr; soc_private->fuse_info.fuse_val[i].fuse_val = fuse_val; for (j = 0; (j < num_fuse) && (j < CAM_CPAS_FUSES_MAX); j++) { if (soc_private->fuse_info.fuse_val[j].fuse_id == fuse_addr) break; } CAM_INFO(CAM_CPAS, "fuse_addr 0x%x, fuse_val %x", if (j >= CAM_CPAS_FUSES_MAX) { CAM_ERR(CAM_CPAS, "fuse_info array overflow! %d", j); goto end; } if (j == num_fuse) { soc_private->fuse_info.fuse_val[j].fuse_id = fuse_addr; soc_private->fuse_info.fuse_val[j].fuse_val = fuse_val; CAM_INFO(CAM_CPAS, "fuse_addr 0x%x, fuse_val %x", fuse_addr, fuse_val); soc_private->fuse_info.num_fuses++; iounmap(fuse); num_fuse++; } } else { /* if fuse ioremap is failed, disable the feature */ CAM_ERR(CAM_CPAS, "fuse register io remap failed fuse_addr:0x%x feature0x%x ", fuse_addr, feature); return 0; if (enable_type == CAM_CPAS_FEATURE_TYPE_ENABLE || enable_type == CAM_CPAS_FEATURE_TYPE_DISABLE) fuse_val = (enable_type) ? ~fuse_mask : fuse_mask; else fuse_val = 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"); if (num_feature >= CAM_CPAS_MAX_FUSE_FEATURE) { CAM_ERR(CAM_CPAS, "feature_info array overflow %d", num_feature); goto end; } 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); soc_private->feature_info[num_feature].feature = feature; soc_private->feature_info[num_feature].hw_map = hw_map; soc_private->feature_info[num_feature].type = enable_type; feature_info = &soc_private->feature_info[num_feature]; 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; if (enable_type != CAM_CPAS_FEATURE_TYPE_VALUE) { if (enable_type == CAM_CPAS_FEATURE_TYPE_ENABLE) { /* * fuse is for enable feature * if fust bit is set means feature is enabled * or HW is enabled */ if (fuse_val & fuse_mask) feature_info->enable = true; else feature_info->enable = false; } else if (enable_type == CAM_CPAS_FEATURE_TYPE_DISABLE){ /* * fuse is for disable feature * if fust bit is set means feature is disabled * or HW is disabled */ if (fuse_val & fuse_mask) feature_info->enable = false; else soc_private->feature_mask &= ~feature_bit_pos; feature_info->enable = true; } else { CAM_ERR(CAM_CPAS, "Feature type not valid, type: %d", enable_type); goto end; } CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x", fuse, fuse_val, soc_private->feature_mask); CAM_INFO(CAM_CPAS, "feature 0x%x enable=%d hw_map=0x%x", feature_info->feature, feature_info->enable, feature_info->hw_map); } else { feature_info->value = (fuse_val & fuse_mask) >> fuse_shift; CAM_INFO(CAM_CPAS, "feature 0x%x value=0x%x hw_map=0x%x", feature_info->feature, feature_info->value, feature_info->hw_map); } num_feature++; iounmap(fuse); } end: soc_private->fuse_info.num_fuses = num_fuse; soc_private->num_feature_info = num_feature; return 0; } Loading @@ -565,7 +633,6 @@ 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); Loading @@ -576,7 +643,6 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, } cam_cpas_get_hw_features(pdev, soc_private); cam_cpas_get_hw_fuse(pdev, soc_private); soc_private->camnoc_axi_min_ib_bw = 0; rc = of_property_read_u64(of_node, Loading drivers/cam_cpas/cam_cpas_soc.h +22 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #define CAM_REGULATOR_LEVEL_MAX 16 #define CAM_CPAS_MAX_TREE_NODES 50 #define CAM_CPAS_MAX_FUSE_FEATURE 10 /** * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping Loading Loading @@ -71,6 +72,23 @@ struct cam_cpas_tree_node { struct cam_cpas_tree_node *parent_node; }; /** * struct cam_cpas_feature_info : CPAS fuse feature info * @feature: Identifier for feature * @type: Type of feature * @value: Fuse value * @enable: Feature enable or disable * @hw_map: Each bit position indicates if the hw_id for the feature */ struct cam_cpas_feature_info { uint32_t feature; uint32_t type; uint32_t value; bool enable; uint32_t hw_map; }; /** * struct cam_cpas_private_soc : CPAS private DT info * Loading @@ -90,9 +108,10 @@ 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 * @fuse_info: fuse information * @rpmh_info: RPMH BCM info * @num_feature_info: number of feature_info entries * @feature_info: Structure for storing feature information */ struct cam_cpas_private_soc { const char *arch_compat; Loading @@ -109,9 +128,10 @@ 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; struct cam_cpas_fuse_info fuse_info; uint32_t rpmh_info[CAM_RPMH_BCM_INFO_MAX]; uint32_t num_feature_info; struct cam_cpas_feature_info feature_info[CAM_CPAS_MAX_FUSE_FEATURE]; }; void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); Loading drivers/cam_cpas/include/cam_cpas_api.h +22 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,22 @@ enum cam_cpas_reg_base { CAM_CPAS_REG_MAX }; /** * enum cam_cpas_hw_index - Enum for identify HW index */ enum cam_cpas_hw_index { CAM_CPAS_HW_IDX_ANY = 0, CAM_CPAS_HW_IDX_0 = 1<<0, CAM_CPAS_HW_IDX_1 = 1<<1, CAM_CPAS_HW_IDX_2 = 1<<2, CAM_CPAS_HW_IDX_3 = 1<<3, CAM_CPAS_HW_IDX_4 = 1<<4, CAM_CPAS_HW_IDX_5 = 1<<5, CAM_CPAS_HW_IDX_6 = 1<<6, CAM_CPAS_HW_IDX_7 = 1<<7, CAM_CPAS_HW_IDX_MAX = 1<<8 }; /** * enum cam_cpas_camera_version Enum for Titan Camera Versions */ Loading Loading @@ -608,11 +624,15 @@ int cam_cpas_get_cpas_hw_version( * * @flag : Camera hw features to check * * @hw_map : To indicate which HWs are supported * * @fule_val : Return fule value in case of value type feature * * @return 1 if feature is supported * */ int cam_cpas_is_feature_supported( uint32_t flag); bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map, uint32_t *fuse_val); /** * cam_cpas_axi_util_path_type_to_string() Loading drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +133 −1 Original line number Diff line number Diff line Loading @@ -1002,6 +1002,116 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, return rc; } bool cam_ife_csid_is_resolution_supported_by_fuse(uint32_t width) { bool supported = true; uint32_t hw_version, fuse_val = UINT_MAX; int rc = 0; rc = cam_cpas_get_cpas_hw_version(&hw_version); if (rc) { CAM_ERR(CAM_ISP, "Could not get CPAS version"); return supported; } switch (hw_version) { case CAM_CPAS_TITAN_570_V200: cam_cpas_is_feature_supported(CAM_CPAS_MP_LIMIT_FUSE, CAM_CPAS_HW_IDX_ANY, &fuse_val); switch (fuse_val) { case 0x0: if (width > CAM_CSID_RESOLUTION_22MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_22MP_WIDTH); supported = false; } break; case 0x1: if (width > CAM_CSID_RESOLUTION_25MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_25MP_WIDTH); supported = false; } break; case 0x2: if (width > CAM_CSID_RESOLUTION_28MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_28MP_WIDTH); supported = false; } break; case UINT_MAX: CAM_WARN(CAM_ISP, "Fuse value not updated"); break; default: CAM_ERR(CAM_ISP, "Fuse value not defined, fuse_val: 0x%x", fuse_val); supported = false; break; } break; default: break; } return supported; } bool cam_ife_csid_is_resolution_supported_by_dt(struct cam_ife_csid_hw *csid_hw, uint32_t width) { bool supported = true; struct cam_hw_soc_info soc_info; struct cam_csid_soc_private *soc_private = NULL; if (!csid_hw || !csid_hw->hw_info) { CAM_ERR(CAM_ISP, "Argument parsing error!"); supported = false; goto end; } soc_info = csid_hw->hw_info->soc_info; soc_private = (struct cam_csid_soc_private *)soc_info.soc_private; if (!soc_private) { CAM_ERR(CAM_ISP, "soc_private not found"); supported = false; goto end; } if (soc_private->max_width_enabled) { if (width > soc_private->max_width) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, soc_private->max_width); supported = false; } } end: return supported; } bool cam_ife_csid_is_resolution_supported(struct cam_ife_csid_hw *csid_hw, uint32_t width) { bool supported = false; if (!csid_hw) { CAM_ERR(CAM_ISP, "csid_hw is NULL"); return supported; } if (cam_ife_csid_is_resolution_supported_by_fuse(width) && cam_ife_csid_is_resolution_supported_by_dt(csid_hw, width)) supported = true; return supported; } int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { Loading Loading @@ -1179,6 +1289,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, } if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->left_stop - reserve->in_port->left_start + 1))) { rc = -EINVAL; goto end; } path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; path_data->width = reserve->in_port->left_width; Loading @@ -1198,6 +1315,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->start_line, path_data->end_line); } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->right_stop - reserve->in_port->right_start + 1))) { rc = -EINVAL; goto end; } path_data->master_idx = reserve->master_idx; CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", csid_hw->hw_intf->hw_idx, path_data->master_idx); Loading @@ -1214,6 +1338,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->start_line, path_data->end_line); } else { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->left_stop - reserve->in_port->left_start + 1))) { rc = -EINVAL; goto end; } path_data->width = reserve->in_port->left_width; path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; Loading Loading @@ -5192,7 +5323,8 @@ 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) if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE, CAM_CPAS_HW_IDX_ANY, NULL)) ife_csid_hw->binning_enable = 1; ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; Loading Loading
drivers/cam_cpas/cam_cpas_intf.c +34 −6 Original line number Diff line number Diff line Loading @@ -119,28 +119,56 @@ 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) bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map, uint32_t *fuse_val) { struct cam_hw_info *cpas_hw = NULL; struct cam_cpas_private_soc *soc_private = NULL; uint32_t feature_mask; bool supported = true; int32_t i; if (!CAM_CPAS_INTF_INITIALIZED()) { CAM_ERR(CAM_CPAS, "cpas intf not initialized"); return -ENODEV; return false; } 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 false; } for (i = 0; i < soc_private->num_feature_info; i++) if (soc_private->feature_info[i].feature == flag) break; if (i == soc_private->num_feature_info) { CAM_INFO(CAM_CPAS, "Feature not found, no of featues: %d", soc_private->num_feature_info); goto end; } if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE || (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_ENABLE)) { if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map) supported = soc_private->feature_info[i].enable; else supported = !soc_private->feature_info[i].enable; } else { if (!fuse_val) { CAM_ERR(CAM_CPAS, "Invalid arg fuse_val"); } else { *fuse_val = soc_private->feature_info[i].value; } } return feature_mask & flag ? 1 : 0; end: return supported; } EXPORT_SYMBOL(cam_cpas_is_feature_supported); Loading
drivers/cam_cpas/cam_cpas_soc.c +125 −59 Original line number Diff line number Diff line Loading @@ -466,87 +466,155 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, return 0; } int cam_cpas_get_hw_fuse(struct platform_device *pdev, 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; memset(&soc_private->fuse_info, 0, sizeof(soc_private->fuse_info)); uint32_t fuse_addr, fuse_mask, fuse_shift; uint32_t val = 0, fuse_val = 0, feature; uint32_t enable_type = 0, hw_map = 0; int count = 0, i = 0, j = 0, num_feature = 0, num_fuse = 0; struct cam_cpas_feature_info *feature_info; of_node = pdev->dev.of_node; count = of_property_count_u32_elems(of_node, "cam_hw_fuse"); CAM_DBG(CAM_CPAS, "fuse info elements count %d", count); if (count <= 0) { CAM_INFO(CAM_CPAS, "no or invalid fuse enrties %d", count); return 0; } else if (count%3 != 0) { CAM_INFO(CAM_CPAS, "fuse entries should be multiple of 3 %d", CAM_INFO(CAM_CPAS, "No or invalid fuse entries count: %d", count); return -EINVAL; goto end; } else if (count%5 != 0) { CAM_INFO(CAM_CPAS, "fuse entries should be multiple of 5 %d", count); goto end; } for (i = 0; i < count; i = i + 3) { for (i = 0; (i + 5) <= count; i = i + 5) { of_property_read_u32_index(of_node, "cam_hw_fuse", i, &feature_bit_pos); &feature); 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_mask); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 3, &enable_type); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 4, &hw_map); val = ffs(fuse_mask); if (val == 0) { CAM_ERR(CAM_CPAS, "fuse_mask not valid 0x%x", fuse_mask); fuse_shift = 0; } else { fuse_shift = val - 1; } CAM_INFO(CAM_CPAS, "feature 0x%x addr 0x%x, mask 0x%x, shift 0x%x type 0x%x hw_map 0x%x", feature, fuse_addr, fuse_mask, fuse_shift, enable_type, hw_map); fuse = ioremap(fuse_addr, 4); if (fuse) { fuse_val = cam_io_r(fuse); soc_private->fuse_info.fuse_val[i].fuse_id = fuse_addr; soc_private->fuse_info.fuse_val[i].fuse_val = fuse_val; for (j = 0; (j < num_fuse) && (j < CAM_CPAS_FUSES_MAX); j++) { if (soc_private->fuse_info.fuse_val[j].fuse_id == fuse_addr) break; } CAM_INFO(CAM_CPAS, "fuse_addr 0x%x, fuse_val %x", if (j >= CAM_CPAS_FUSES_MAX) { CAM_ERR(CAM_CPAS, "fuse_info array overflow! %d", j); goto end; } if (j == num_fuse) { soc_private->fuse_info.fuse_val[j].fuse_id = fuse_addr; soc_private->fuse_info.fuse_val[j].fuse_val = fuse_val; CAM_INFO(CAM_CPAS, "fuse_addr 0x%x, fuse_val %x", fuse_addr, fuse_val); soc_private->fuse_info.num_fuses++; iounmap(fuse); num_fuse++; } } else { /* if fuse ioremap is failed, disable the feature */ CAM_ERR(CAM_CPAS, "fuse register io remap failed fuse_addr:0x%x feature0x%x ", fuse_addr, feature); return 0; if (enable_type == CAM_CPAS_FEATURE_TYPE_ENABLE || enable_type == CAM_CPAS_FEATURE_TYPE_DISABLE) fuse_val = (enable_type) ? ~fuse_mask : fuse_mask; else fuse_val = 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"); if (num_feature >= CAM_CPAS_MAX_FUSE_FEATURE) { CAM_ERR(CAM_CPAS, "feature_info array overflow %d", num_feature); goto end; } 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); soc_private->feature_info[num_feature].feature = feature; soc_private->feature_info[num_feature].hw_map = hw_map; soc_private->feature_info[num_feature].type = enable_type; feature_info = &soc_private->feature_info[num_feature]; 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; if (enable_type != CAM_CPAS_FEATURE_TYPE_VALUE) { if (enable_type == CAM_CPAS_FEATURE_TYPE_ENABLE) { /* * fuse is for enable feature * if fust bit is set means feature is enabled * or HW is enabled */ if (fuse_val & fuse_mask) feature_info->enable = true; else feature_info->enable = false; } else if (enable_type == CAM_CPAS_FEATURE_TYPE_DISABLE){ /* * fuse is for disable feature * if fust bit is set means feature is disabled * or HW is disabled */ if (fuse_val & fuse_mask) feature_info->enable = false; else soc_private->feature_mask &= ~feature_bit_pos; feature_info->enable = true; } else { CAM_ERR(CAM_CPAS, "Feature type not valid, type: %d", enable_type); goto end; } CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x", fuse, fuse_val, soc_private->feature_mask); CAM_INFO(CAM_CPAS, "feature 0x%x enable=%d hw_map=0x%x", feature_info->feature, feature_info->enable, feature_info->hw_map); } else { feature_info->value = (fuse_val & fuse_mask) >> fuse_shift; CAM_INFO(CAM_CPAS, "feature 0x%x value=0x%x hw_map=0x%x", feature_info->feature, feature_info->value, feature_info->hw_map); } num_feature++; iounmap(fuse); } end: soc_private->fuse_info.num_fuses = num_fuse; soc_private->num_feature_info = num_feature; return 0; } Loading @@ -565,7 +633,6 @@ 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); Loading @@ -576,7 +643,6 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, } cam_cpas_get_hw_features(pdev, soc_private); cam_cpas_get_hw_fuse(pdev, soc_private); soc_private->camnoc_axi_min_ib_bw = 0; rc = of_property_read_u64(of_node, Loading
drivers/cam_cpas/cam_cpas_soc.h +22 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #define CAM_REGULATOR_LEVEL_MAX 16 #define CAM_CPAS_MAX_TREE_NODES 50 #define CAM_CPAS_MAX_FUSE_FEATURE 10 /** * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping Loading Loading @@ -71,6 +72,23 @@ struct cam_cpas_tree_node { struct cam_cpas_tree_node *parent_node; }; /** * struct cam_cpas_feature_info : CPAS fuse feature info * @feature: Identifier for feature * @type: Type of feature * @value: Fuse value * @enable: Feature enable or disable * @hw_map: Each bit position indicates if the hw_id for the feature */ struct cam_cpas_feature_info { uint32_t feature; uint32_t type; uint32_t value; bool enable; uint32_t hw_map; }; /** * struct cam_cpas_private_soc : CPAS private DT info * Loading @@ -90,9 +108,10 @@ 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 * @fuse_info: fuse information * @rpmh_info: RPMH BCM info * @num_feature_info: number of feature_info entries * @feature_info: Structure for storing feature information */ struct cam_cpas_private_soc { const char *arch_compat; Loading @@ -109,9 +128,10 @@ 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; struct cam_cpas_fuse_info fuse_info; uint32_t rpmh_info[CAM_RPMH_BCM_INFO_MAX]; uint32_t num_feature_info; struct cam_cpas_feature_info feature_info[CAM_CPAS_MAX_FUSE_FEATURE]; }; void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); Loading
drivers/cam_cpas/include/cam_cpas_api.h +22 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,22 @@ enum cam_cpas_reg_base { CAM_CPAS_REG_MAX }; /** * enum cam_cpas_hw_index - Enum for identify HW index */ enum cam_cpas_hw_index { CAM_CPAS_HW_IDX_ANY = 0, CAM_CPAS_HW_IDX_0 = 1<<0, CAM_CPAS_HW_IDX_1 = 1<<1, CAM_CPAS_HW_IDX_2 = 1<<2, CAM_CPAS_HW_IDX_3 = 1<<3, CAM_CPAS_HW_IDX_4 = 1<<4, CAM_CPAS_HW_IDX_5 = 1<<5, CAM_CPAS_HW_IDX_6 = 1<<6, CAM_CPAS_HW_IDX_7 = 1<<7, CAM_CPAS_HW_IDX_MAX = 1<<8 }; /** * enum cam_cpas_camera_version Enum for Titan Camera Versions */ Loading Loading @@ -608,11 +624,15 @@ int cam_cpas_get_cpas_hw_version( * * @flag : Camera hw features to check * * @hw_map : To indicate which HWs are supported * * @fule_val : Return fule value in case of value type feature * * @return 1 if feature is supported * */ int cam_cpas_is_feature_supported( uint32_t flag); bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map, uint32_t *fuse_val); /** * cam_cpas_axi_util_path_type_to_string() Loading
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +133 −1 Original line number Diff line number Diff line Loading @@ -1002,6 +1002,116 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, return rc; } bool cam_ife_csid_is_resolution_supported_by_fuse(uint32_t width) { bool supported = true; uint32_t hw_version, fuse_val = UINT_MAX; int rc = 0; rc = cam_cpas_get_cpas_hw_version(&hw_version); if (rc) { CAM_ERR(CAM_ISP, "Could not get CPAS version"); return supported; } switch (hw_version) { case CAM_CPAS_TITAN_570_V200: cam_cpas_is_feature_supported(CAM_CPAS_MP_LIMIT_FUSE, CAM_CPAS_HW_IDX_ANY, &fuse_val); switch (fuse_val) { case 0x0: if (width > CAM_CSID_RESOLUTION_22MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_22MP_WIDTH); supported = false; } break; case 0x1: if (width > CAM_CSID_RESOLUTION_25MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_25MP_WIDTH); supported = false; } break; case 0x2: if (width > CAM_CSID_RESOLUTION_28MP_WIDTH) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, CAM_CSID_RESOLUTION_28MP_WIDTH); supported = false; } break; case UINT_MAX: CAM_WARN(CAM_ISP, "Fuse value not updated"); break; default: CAM_ERR(CAM_ISP, "Fuse value not defined, fuse_val: 0x%x", fuse_val); supported = false; break; } break; default: break; } return supported; } bool cam_ife_csid_is_resolution_supported_by_dt(struct cam_ife_csid_hw *csid_hw, uint32_t width) { bool supported = true; struct cam_hw_soc_info soc_info; struct cam_csid_soc_private *soc_private = NULL; if (!csid_hw || !csid_hw->hw_info) { CAM_ERR(CAM_ISP, "Argument parsing error!"); supported = false; goto end; } soc_info = csid_hw->hw_info->soc_info; soc_private = (struct cam_csid_soc_private *)soc_info.soc_private; if (!soc_private) { CAM_ERR(CAM_ISP, "soc_private not found"); supported = false; goto end; } if (soc_private->max_width_enabled) { if (width > soc_private->max_width) { CAM_ERR(CAM_ISP, "Resolution not supported required_width: %d max_supported_width: %d", width, soc_private->max_width); supported = false; } } end: return supported; } bool cam_ife_csid_is_resolution_supported(struct cam_ife_csid_hw *csid_hw, uint32_t width) { bool supported = false; if (!csid_hw) { CAM_ERR(CAM_ISP, "csid_hw is NULL"); return supported; } if (cam_ife_csid_is_resolution_supported_by_fuse(width) && cam_ife_csid_is_resolution_supported_by_dt(csid_hw, width)) supported = true; return supported; } int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { Loading Loading @@ -1179,6 +1289,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, } if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->left_stop - reserve->in_port->left_start + 1))) { rc = -EINVAL; goto end; } path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; path_data->width = reserve->in_port->left_width; Loading @@ -1198,6 +1315,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->start_line, path_data->end_line); } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->right_stop - reserve->in_port->right_start + 1))) { rc = -EINVAL; goto end; } path_data->master_idx = reserve->master_idx; CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", csid_hw->hw_intf->hw_idx, path_data->master_idx); Loading @@ -1214,6 +1338,13 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->start_line, path_data->end_line); } else { if ((reserve->res_id == CAM_IFE_PIX_PATH_RES_IPP) && !(cam_ife_csid_is_resolution_supported(csid_hw, reserve->in_port->left_stop - reserve->in_port->left_start + 1))) { rc = -EINVAL; goto end; } path_data->width = reserve->in_port->left_width; path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; Loading Loading @@ -5192,7 +5323,8 @@ 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) if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE, CAM_CPAS_HW_IDX_ANY, NULL)) ife_csid_hw->binning_enable = 1; ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; Loading