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

Commit fe2f879a authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: cpas: Add fuse MP limit support" into camera-kernel.lnx.4.0

parents 36a18d22 c37f48cf
Loading
Loading
Loading
Loading
+34 −6
Original line number Diff line number Diff line
@@ -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);

+125 −59
Original line number Diff line number Diff line
@@ -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;
}

@@ -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);
@@ -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,
+22 −2
Original line number Diff line number Diff line
@@ -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
@@ -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
 *
@@ -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;
@@ -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);
+22 −2
Original line number Diff line number Diff line
@@ -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
 */
@@ -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()
+133 −1
Original line number Diff line number Diff line
@@ -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)
{
@@ -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;
@@ -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);
@@ -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;
@@ -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