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

Commit ce2c04e9 authored by David Collins's avatar David Collins
Browse files

regulator: cpr3-regulator: add support for corners above max fuse corner



Add support for fuse corner to corner mappings in which the
highest fuse corner is mapped to a corner lower than the
highest corner.  This can be used to define a corner which has
a constant voltage offset above the highest fuse corner but which
does not impact interpolation for the lower corners.

Change-Id: Ie41522cb06ca81898f58458694067a567f608df0
CRs-Fixed: 981475
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent 83807eec
Loading
Loading
Loading
Loading
+23 −26
Original line number Diff line number Diff line
@@ -693,19 +693,8 @@ static int cpr3_msm8996_hmss_calculate_open_loop_voltages(
		goto done;
	}

	/* Determine highest corner mapped to each fuse corner */
	j = vreg->fuse_corner_count - 1;
	for (i = vreg->corner_count - 1; i >= 0; i--) {
		if (vreg->corner[i].cpr_fuse_corner == j) {
			fmax_corner[j] = i;
			j--;
		}
	}
	if (j >= 0) {
		cpr3_err(vreg, "invalid fuse corner mapping\n");
		rc = -EINVAL;
		goto done;
	}
	for (i = 0; i < vreg->fuse_corner_count; i++)
		fmax_corner[i] = vreg->fuse_corner_map[i];

	/*
	 * Interpolation is not possible for corners mapped to the lowest fuse
@@ -714,6 +703,14 @@ static int cpr3_msm8996_hmss_calculate_open_loop_voltages(
	for (i = 0; i <= fmax_corner[0]; i++)
		vreg->corner[i].open_loop_volt = fuse_volt[0];

	/*
	 * Interpolation is not possible for corners mapped above the highest
	 * fuse corner so use the fuse corner value directly.
	 */
	j = vreg->fuse_corner_count - 1;
	for (i = fmax_corner[j] + 1; i < vreg->corner_count; i++)
		vreg->corner[i].open_loop_volt = fuse_volt[j];

	/*
	 * Corner LowSVS should be skipped for voltage interpolation
	 * since no fuse exists for it.  Instead, the lowest interpolation
@@ -874,19 +871,8 @@ static int cpr3_msm8996_hmss_calculate_target_quotients(
				volt_adjust, volt_adjust_fuse, ro_scale);
	}

	/* Determine highest corner mapped to each fuse corner */
	j = vreg->fuse_corner_count - 1;
	for (i = vreg->corner_count - 1; i >= 0; i--) {
		if (vreg->corner[i].cpr_fuse_corner == j) {
			fmax_corner[j] = i;
			j--;
		}
	}
	if (j >= 0) {
		cpr3_err(vreg, "invalid fuse corner mapping\n");
		rc = -EINVAL;
		goto done;
	}
	for (i = 0; i < vreg->fuse_corner_count; i++)
		fmax_corner[i] = vreg->fuse_corner_map[i];

	/*
	 * Interpolation is not possible for corners mapped to the lowest fuse
@@ -903,6 +889,17 @@ static int cpr3_msm8996_hmss_calculate_target_quotients(
	for (i = 0; i <= fmax_corner[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS]; i++)
		vreg->corner[i].target_quot[ro] = quot;

	/*
	 * Interpolation is not possible for corners mapped above the highest
	 * fuse corner so use the fuse corner value directly.
	 */
	j = vreg->fuse_corner_count - 1;
	quot_adjust = cpr3_quot_adjustment(ro_scale[j], volt_adjust_fuse[j]);
	quot = fuse->target_quot[j] + quot_adjust;
	ro = fuse->ro_sel[j];
	for (i = fmax_corner[j] + 1; i < vreg->corner_count; i++)
		vreg->corner[i].target_quot[ro] = quot;

	/*
	 * The LowSVS target quotient is defined as:
	 *	(SVS target quotient) - (the unpacked SVS quotient offset)
+9 −0
Original line number Diff line number Diff line
@@ -210,6 +210,14 @@ struct cprh_corner_band {
 * @fuse_combos_supported: The number of fuse combinations supported by the
 *			device tree configuration for this CPR3 regulator
 * @fuse_corner_count:	Number of corners defined by fuse parameters
 * @fuse_corner_map:	Array of length fuse_corner_count which specifies the
 *			highest corner associated with each fuse corner.  Note
 *			that each element must correspond to a valid corner
 *			and that element values must be strictly increasing.
 *			Also, it is acceptable for the lowest fuse corner to map
 *			to a corner other than the lowest.  Likewise, it is
 *			acceptable for the highest fuse corner to map to a
 *			corner other than the highest.
 * @fuse_combo_corner_sum: The sum of the corner counts across all fuse combos
 * @fuse_combo_offset:	The device tree property array offset for the selected
 *			fuse combo
@@ -308,6 +316,7 @@ struct cpr3_regulator {
	int			fuse_combo;
	int			fuse_combos_supported;
	int			fuse_corner_count;
	int			*fuse_corner_map;
	int			fuse_combo_corner_sum;
	int			fuse_combo_offset;
	int			speed_bin_corner_sum;
+22 −8
Original line number Diff line number Diff line
@@ -528,9 +528,9 @@ int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
 * and qcom,cpr-corner-fmax-map.
 *
 * It initializes these CPR3 regulator elements: corner, corner_count,
 * fuse_combos_supported, and speed_bins_supported.  It initializes these
 * elements for each corner: ceiling_volt, floor_volt, proc_freq, and
 * cpr_fuse_corner.
 * fuse_combos_supported, fuse_corner_map, and speed_bins_supported.  It
 * initializes these elements for each corner: ceiling_volt, floor_volt,
 * proc_freq, and cpr_fuse_corner.
 *
 * It requires that the following CPR3 regulator elements be initialized before
 * being called: fuse_corner_count, fuse_combo, and speed_bin_fuse.
@@ -748,11 +748,19 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
		}
	}

	vreg->fuse_corner_map = devm_kcalloc(ctrl->dev, vreg->fuse_corner_count,
				    sizeof(*vreg->fuse_corner_map), GFP_KERNEL);
	if (!vreg->fuse_corner_map) {
		rc = -ENOMEM;
		goto free_temp;
	}

	rc = cpr3_parse_array_property(vreg, "qcom,cpr-corner-fmax-map",
		vreg->fuse_corner_count, temp);
	if (rc)
		goto free_temp;
	for (i = 0; i < vreg->fuse_corner_count; i++) {
		vreg->fuse_corner_map[i] = temp[i] - CPR3_CORNER_OFFSET;
		if (temp[i] < CPR3_CORNER_OFFSET
		    || temp[i] > vreg->corner_count + CPR3_CORNER_OFFSET) {
			cpr3_err(vreg, "invalid corner value specified in qcom,cpr-corner-fmax-map: %u\n",
@@ -766,13 +774,11 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
			goto free_temp;
		}
	}
	if (temp[vreg->fuse_corner_count - 1] != vreg->corner_count) {
		cpr3_err(vreg, "highest Fmax corner %u in qcom,cpr-corner-fmax-map does not match highest supported corner %d\n",
	if (temp[vreg->fuse_corner_count - 1] != vreg->corner_count)
		cpr3_debug(vreg, "Note: highest Fmax corner %u in qcom,cpr-corner-fmax-map does not match highest supported corner %d\n",
			temp[vreg->fuse_corner_count - 1],
			vreg->corner_count);
		rc = -EINVAL;
		goto free_temp;
	}

	for (i = 0; i < vreg->corner_count; i++) {
		for (j = 0; j < vreg->fuse_corner_count; j++) {
			if (i + CPR3_CORNER_OFFSET <= temp[j]) {
@@ -780,6 +786,14 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
				break;
			}
		}
		if (j == vreg->fuse_corner_count) {
			/*
			 * Handle the case where the highest fuse corner maps
			 * to a corner below the highest corner.
			 */
			vreg->corner[i].cpr_fuse_corner
				= vreg->fuse_corner_count - 1;
		}
	}

	if (of_find_property(vreg->of_node,