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

Commit 1531214f authored by David Collins's avatar David Collins
Browse files

regulator: cpr-regulator: add support for target quotient unpacking



Some SoCs have extremely limited fuse space.  In order to save
fuse bits, the CPR target quotients are packed to take up less
space.  Add support to unpack the target quotient for each fuse
corner using an offset and multiplier.

Change-Id: Ie1b49b8e881dbb239277876c8a4ae8603832e878
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent 3cbee4bc
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -176,6 +176,16 @@ Optional properties:
				array are ordered from lowest voltage corner to highest voltage corner.
				If this property is not present, then all target quotient fuse values
				are assumed to be the default length of 12 bits.
- qcom,cpr-fuse-target-quot-scale:	Array of doubles which defines the scaling coefficients to decode
				the target quotients of each fuse corner.  The first element in each
				double represents the offset to add to the scaled quotient.  The second
				element represents the multiplier to scale the quotient by.  For example,
				given a tuple <A B>, quot_decoded = A + (B * quot_raw).
				The doubles in the array are ordered from lowest voltage corner to highest
				voltage corner.  This property must contain a number of doubles equal to
				the value of qcom,cpr-fuse-corners.  If this property is not present,
				then all target quotient parameters are assumed to have an offset of 0
				and a multiplier of 1 (i.e. no decoding needed).
- qcom,cpr-enable:		Present: CPR enabled by default.
				Not Present: CPR disable by default.
- qcom,cpr-fuse-cond-min-volt-sel:	Array of 5 elements to indicate where to read the bits,  what value to
@@ -410,6 +420,10 @@ Example:
				<1 1 2 4 12>,
				<2 1 2 4 10>,
				<5 1 2 4 14>;
		qcom,cpr-fuse-target-quot-scale =
				<0 1>,
				<0 1>,
				<0 1>;
		qcom,cpr-quot-adjust-scaling-factor-max = <650>;
		qcom,cpr-fuse-init-voltage =
				<27 36 6 0>,
+44 −1
Original line number Diff line number Diff line
@@ -1886,6 +1886,11 @@ free_arrays:
	return rc;
}

struct cpr_quot_scale {
	u32 offset;
	u32 multiplier;
};

static int cpr_init_cpr_efuse(struct platform_device *pdev,
				     struct cpr_regulator *cpr_vreg)
{
@@ -1903,6 +1908,7 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev,
	u64 fuse_bits, fuse_bits_2;
	u32 *quot_adjust;
	u32 *target_quot_size;
	struct cpr_quot_scale *quot_scale;

	len = cpr_vreg->num_fuse_corners + 1;

@@ -1910,9 +1916,10 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev,
	bp_ro_sel = kzalloc(len * sizeof(*bp_ro_sel), GFP_KERNEL);
	quot_adjust = kzalloc(len * sizeof(*quot_adjust), GFP_KERNEL);
	target_quot_size = kzalloc(len * sizeof(*target_quot_size), GFP_KERNEL);
	quot_scale = kzalloc(len * sizeof(*quot_scale), GFP_KERNEL);

	if (bp_target_quot == NULL || bp_ro_sel == NULL || quot_adjust == NULL
	    || target_quot_size == NULL) {
	    || target_quot_size == NULL || quot_scale == NULL) {
		pr_err("Could not allocate memory for fuse parsing arrays\n");
		rc = -ENOMEM;
		goto error;
@@ -1973,6 +1980,38 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev,
			target_quot_size[i] = CPR_FUSE_TARGET_QUOT_BITS;
	}

	if (of_property_read_bool(of_node, "qcom,cpr-fuse-target-quot-scale")) {
		for (i = 0; i < cpr_vreg->num_fuse_corners; i++) {
			rc = of_property_read_u32_index(of_node,
				"qcom,cpr-fuse-target-quot-scale", i * 2,
				&quot_scale[i + CPR_FUSE_CORNER_MIN].offset);
			if (rc < 0) {
				pr_err("error while reading qcom,cpr-fuse-target-quot-scale: rc=%d\n",
					rc);
				goto error;
			}

			rc = of_property_read_u32_index(of_node,
				"qcom,cpr-fuse-target-quot-scale", i * 2 + 1,
			       &quot_scale[i + CPR_FUSE_CORNER_MIN].multiplier);
			if (rc < 0) {
				pr_err("error while reading qcom,cpr-fuse-target-quot-scale: rc=%d\n",
					rc);
				goto error;
			}
		}
	} else {
		/*
		 * In the default case, target quotients require no scaling so
		 * use offset = 0, multiplier = 1.
		 */
		for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
		     i++) {
			quot_scale[i].offset = 0;
			quot_scale[i].multiplier = 1;
		}
	}

	rc = of_property_read_u32_array(of_node, ro_sel_str,
		&bp_ro_sel[CPR_FUSE_CORNER_MIN], cpr_vreg->num_fuse_corners);
	if (rc < 0) {
@@ -2075,6 +2114,9 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev,
			= cpr_read_efuse_param(cpr_vreg, cpr_fuse_row[0],
				bp_target_quot[i], target_quot_size[i],
				cpr_fuse_row[1]);
		/* Unpack the target quotient by scaling. */
		cpr_vreg->cpr_fuse_target_quot[i] *= quot_scale[i].multiplier;
		cpr_vreg->cpr_fuse_target_quot[i] += quot_scale[i].offset;
		pr_info("Corner[%d]: ro_sel = %d, target quot = %d\n", i,
			cpr_vreg->cpr_fuse_ro_sel[i],
			cpr_vreg->cpr_fuse_target_quot[i]);
@@ -2138,6 +2180,7 @@ error:
	kfree(bp_ro_sel);
	kfree(quot_adjust);
	kfree(target_quot_size);
	kfree(quot_scale);

	return rc;
}