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

Commit b2d58529 authored by Tirupathi Reddy's avatar Tirupathi Reddy
Browse files

regulator: cpr4-apss: Update APC CPR fuse combo logic for msm8953



Add new fuse combo logic variant to support variable number of selection
parameters and also optimize the number of possible fuse combinations
by defining a mapping from combinations of fuse parameter ranges to
fuse combo ID.

CRs-Fixed: 1055190
Change-Id: I840a7d4120eebeaf0fec1409580ba4919b946a61
Signed-off-by: default avatarTirupathi Reddy <tirupath@codeaurora.org>
parent e7587c62
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ APSS specific properties:
		    and Turbo.

- qcom,cpr-fuse-combos
	Usage:      required
	Usage:      optional
	Value type: <u32>
	Definition: Specifies the number of fuse combinations being supported by
		    the device.  This value is utilized by several other
@@ -178,6 +178,11 @@ APSS specific properties:
		    The last 8 fuse combos correspond to speed bin fuse value 7
		    along with CPR revision fuse values 0 to 7.

		    This property must be specified unless qcom,cpr-fuse-combo-map
		    is present. In that case, qcom,cpr-fuse-combos is implicitly
		    assumed to have a value equal to the number of tuple lists (rows)
		    found in the qcom,cpr-fuse-combo-map property.

- qcom,cpr-speed-bins
	Usage:      optional
	Value type: <u32>
@@ -368,6 +373,27 @@ APSS specific properties:
		    speed bins 1-to-1 or exactly 1 list which is used regardless
		    of the speed bin found on a given chip.

- qcom,cpr-fuse-combo-map
	Usage:      optional
	Value type: <prop-encoded-array>
	Definition: A grouping of integer tuple lists where each tuple list (row)
		    defines a mapping from combinations of fuse parameter ranges
		    to fuse combo ID (i.e., map row index). Each tuple defines the
		    beginning and ending fuse parameter value that matches. The
		    number of tuples in each row is equal to the number of selection
		    fuse parameters used in fuse combo logic. For MSM8953, the fuse
		    parameters are "speed-bin", "cpr fuse revision", and "foundry id".
		    The tuples in each row correspond to the fuses in order:
		    "speed-bin", "cpr fuse revision" and "foundry id". An example entry
		    for speed-bin '3', cpr fuse revisions >= '2', and foundry '2' is
		    as shown below:
		         <3 3>, <2 7>, <2 2>

		    The number of rows in the property is arbitrary but used to size
		    other properties. qcom,cpr-fuse-combos must be set to the number
		    of rows specified in this property. For msm8953, the maximum number
		    of rows for this property is 512 (8 * 8 * 8).

=======
Example
=======
+8 −0
Original line number Diff line number Diff line
@@ -863,6 +863,8 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
			bool use_corner_band);
int cpr3_apm_init(struct cpr3_controller *ctrl);
int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val,
			int fuse_count);

#else

@@ -1035,6 +1037,12 @@ static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
	return 0;
}

static int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val,
			int fuse_count)
{
	return -EPERM;
}

#endif /* CONFIG_REGULATOR_CPR3 */

#endif /* __REGULATOR_CPR_REGULATOR_H__ */
+104 −22
Original line number Diff line number Diff line
@@ -562,6 +562,14 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
		return -EINVAL;
	}

	/*
	 * Check if CPR3 regulator's fuse_combos_supported element is already
	 * populated by fuse-combo-map logic. If not populated, then parse the
	 * qcom,cpr-fuse-combos property.
	 */
	if (vreg->fuse_combos_supported)
		max_fuse_combos = vreg->fuse_combos_supported;
	else {
		rc = of_property_read_u32(node, "qcom,cpr-fuse-combos",
					&max_fuse_combos);
		if (rc) {
@@ -571,8 +579,8 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
		}

		/*
	 * Sanity check against arbitrarily large value to avoid excessive
	 * memory allocation.
		 * Sanity check against arbitrarily large value to avoid
		 * excessive memory allocation.
		 */
		if (max_fuse_combos > 100 || max_fuse_combos == 0) {
			cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n",
@@ -588,6 +596,7 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
		}

		vreg->fuse_combos_supported = max_fuse_combos;
	}

	of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins);

@@ -1974,3 +1983,76 @@ done:

	return rc;
}

/**
 * cpr3_parse_fuse_combo_map() - parse fuse combo map data for a CPR3 regulator
 *		from device tree.
 * @vreg:		Pointer to the CPR3 regulator
 * @fuse_val:		Array of selection fuse parameter values
 * @fuse_count:		Number of selection fuse parameters used in fuse combo
 *			map
 *
 * This function reads the qcom,cpr-fuse-combo-map device tree property and
 * populates the fuse_combo element of CPR3 regulator with the row number of
 * fuse combo map data that matches with the data in fuse_val input array.
 *
 * Return: 0 on success, -ENODEV if qcom,cpr-fuse-combo-map property is not
 *		specified in device node, other errno on failure
 */
int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val,
			int fuse_count)
{
	struct device_node *node = vreg->of_node;
	int i, j, len, num_fuse_combos, row_size, rc = 0;
	u32 *tmp;

	if (!of_find_property(node, "qcom,cpr-fuse-combo-map", &len)) {
		/* property not specified */
		return -ENODEV;
	}

	row_size = fuse_count * 2;
	if (len == 0 || len % (sizeof(u32) * row_size)) {
		cpr3_err(vreg, "qcom,cpr-fuse-combo-map length=%d is invalid\n",
			len);
		return -EINVAL;
	}

	num_fuse_combos = len / (sizeof(u32) * row_size);
	vreg->fuse_combos_supported = num_fuse_combos;

	tmp = kzalloc(len, GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	rc = of_property_read_u32_array(node, "qcom,cpr-fuse-combo-map",
			tmp, num_fuse_combos * row_size);
	if (rc) {
		cpr3_err(vreg, "could not read qcom,cpr-fuse-combo-map, rc=%d\n",
			rc);
		goto done;
	}

	for (i = 0; i < num_fuse_combos; i++) {
		for (j = 0; j < fuse_count; j++) {
			if (tmp[i * row_size + j * 2] > fuse_val[j]
			      || tmp[i * row_size + j * 2 + 1] < fuse_val[j])
				break;
		}
		if (j == fuse_count) {
			vreg->fuse_combo = i;
			break;
		}
	}

	if (i >= num_fuse_combos) {
		cpr3_err(vreg, "No matching CPR fuse combo found!\n");
		BUG_ON(1);
		rc = -EINVAL;
		goto done;
	}

done:
	kfree(tmp);
	return rc;
}
+84 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@
 * @speed_bin:		Application processor speed bin fuse parameter value for
 *			the given chip
 * @cpr_fusing_rev:	CPR fusing revision fuse parameter value
 * @foundry_id:		Foundry identifier fuse parameter value for the given
 *			chip
 * @boost_cfg:		CPR boost configuration fuse parameter value
 * @boost_voltage:	CPR boost voltage fuse parameter value (raw, not
 *			converted to a voltage)
@@ -66,6 +68,7 @@ struct cpr4_msm8953_apss_fuses {
	u64	quot_offset[MSM8953_APSS_FUSE_CORNERS];
	u64	speed_bin;
	u64	cpr_fusing_rev;
	u64	foundry_id;
	u64	boost_cfg;
	u64	boost_voltage;
	u64	misc;
@@ -149,6 +152,11 @@ static const struct cpr3_fuse_param msm8953_apss_speed_bin_param[] = {
	{},
};

static const struct cpr3_fuse_param msm8953_apss_foundry_id_param[] = {
	{37, 40, 42},
	{},
};

static const struct cpr3_fuse_param msm8953_cpr_boost_fuse_cfg_param[] = {
	{36, 43, 45},
	{},
@@ -170,6 +178,15 @@ static const struct cpr3_fuse_param msm8953_apss_aging_init_quot_diff_param[]
	{},
};

/*
 * The maximum number of fuse combinations possible for the selected fuse
 * parameters in fuse combo map logic.
 * Here, possible speed-bin values = 8, fuse revision values = 8, and foundry
 * identifier values = 8. Total number of combinations = 512 (i.e., 8 * 8 * 8)
 */
#define CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT	512


/*
 * The number of possible values for misc fuse is
 * 2^(#bits defined for misc fuse)
@@ -260,6 +277,14 @@ static int cpr4_msm8953_apss_read_fuse_data(struct cpr3_regulator *vreg)
	}
	cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);

	rc = cpr3_read_fuse_param(base, msm8953_apss_foundry_id_param,
				&fuse->foundry_id);
	if (rc) {
		cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc);
		return rc;
	}
	cpr3_info(vreg, "foundry id = %llu\n", fuse->foundry_id);

	rc = cpr3_read_fuse_param(base, msm8953_misc_fuse_volt_adj_param,
				&fuse->misc);
	if (rc) {
@@ -1145,6 +1170,58 @@ done:
	return rc;
}

/*
 * Constants which define the selection fuse parameters used in fuse combo map
 * logic.
 */
enum cpr4_msm8953_apss_fuse_combo_parameters {
	MSM8953_APSS_SPEED_BIN = 0,
	MSM8953_APSS_CPR_FUSE_REV,
	MSM8953_APSS_FOUNDRY_ID,
	MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
};

/**
 * cpr4_parse_fuse_combo_map() - parse APSS fuse combo map data from device tree
 *		properties of the CPR3 regulator's device node
 * @vreg:		Pointer to the CPR3 regulator
 *
 * Return: 0 on success, errno on failure
 */
static int cpr4_parse_fuse_combo_map(struct cpr3_regulator *vreg)
{
	struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
	u64 *fuse_val;
	int rc;

	fuse_val = kcalloc(MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
			sizeof(*fuse_val), GFP_KERNEL);
	if (!fuse_val)
		return -ENOMEM;

	fuse_val[MSM8953_APSS_SPEED_BIN] = fuse->speed_bin;
	fuse_val[MSM8953_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev;
	fuse_val[MSM8953_APSS_FOUNDRY_ID] = fuse->foundry_id;
	rc = cpr3_parse_fuse_combo_map(vreg, fuse_val,
			MSM8953_APSS_FUSE_COMBO_PARAM_COUNT);
	if (rc == -ENODEV) {
		cpr3_debug(vreg, "using legacy fuse combo logic, rc=%d\n",
			rc);
		rc = 0;
	} else if (rc < 0) {
		cpr3_err(vreg, "error reading fuse combo map data, rc=%d\n",
			rc);
	} else if (vreg->fuse_combo >=
			CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT) {
		cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
			vreg->fuse_combo);
		rc = -EINVAL;
	}

	kfree(fuse_val);
	return rc;
}

/**
 * cpr4_apss_init_regulator() - perform all steps necessary to initialize the
 *		configuration data for a CPR3 regulator
@@ -1165,6 +1242,13 @@ static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg)

	fuse = vreg->platform_fuses;

	rc = cpr4_parse_fuse_combo_map(vreg);
	if (rc) {
		cpr3_err(vreg, "error while parsing fuse combo map, rc=%d\n",
			rc);
		return rc;
	}

	rc = cpr4_apss_parse_corner_data(vreg);
	if (rc) {
		cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",