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

Commit 8abecc27 authored by Osvaldo Banuelos's avatar Osvaldo Banuelos
Browse files

regulator: cpr3-hmss-regulator: configure retention voltage based on fuses



Add support to determine the HMSS retention voltage based on
data read from hardware fuses. In particular, the CPU retention
voltage is defined to be the maximum of the VDD_MX and VDD_APCC retention
voltages, both of which are available in the fuse region. Read these
fuses and configure the LDO retention regulator to the HMSS retention
voltage when the CPR3 HMSS regulator driver probes.

Change-Id: If5e319f3b4395d4a4a230e900e545e5ec9e78eba
Signed-off-by: default avatarOsvaldo Banuelos <osvaldob@codeaurora.org>
parent 07179574
Loading
Loading
Loading
Loading
+151 −91
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@
 * @limitation:		CPR limitation select fuse parameter value
 * @partial_binning:	Chip partial binning fuse parameter value which defines
 *			limitations found on a given chip
 * @vdd_mx_ret_fuse:	Defines the logic retention voltage of VDD_MX
 * @vdd_apcc_ret_fuse:	Defines the logic retention voltage of VDD_APCC
 *
 * This struct holds the values for all of the fuses read from memory.  The
 * values for ro_sel, init_voltage, target_quot, and quot_offset come from
@@ -72,6 +74,8 @@ struct cpr3_msm8996_hmss_fuses {
	u64	redundant_fusing;
	u64	limitation;
	u64	partial_binning;
	u64	vdd_mx_ret_fuse;
	u64	vdd_apcc_ret_fuse;
};

/**
@@ -318,6 +322,16 @@ static const struct cpr3_fuse_param msm8996_cpr_limitation_param[] = {
	{},
};

static const struct cpr3_fuse_param msm8996_vdd_mx_ret_param[] = {
	{41, 2, 4},
	{},
};

static const struct cpr3_fuse_param msm8996_vdd_apcc_ret_param[] = {
	{41, 52, 54},
	{},
};

static const struct cpr3_fuse_param msm8996_cpr_partial_binning_param[] = {
	{39, 55, 59},
	{},
@@ -364,6 +378,15 @@ static const int msm8996_v3_hmss_fuse_ref_volt[MSM8996_HMSS_FUSE_CORNERS] = {
	1140000,
};

/* Defines mapping from retention fuse values to voltages in microvolts */
static const int msm8996_vdd_apcc_fuse_ret_volt[] = {
	600000, 550000, 500000, 450000, 400000, 350000, 300000, 600000,
};

static const int msm8996_vdd_mx_fuse_ret_volt[] = {
	700000, 650000, 580000, 550000, 490000, 490000, 490000, 490000,
};

#define MSM8996_HMSS_FUSE_STEP_VOLT		10000
#define MSM8996_HMSS_VOLTAGE_FUSE_SIZE		6
#define MSM8996_HMSS_QUOT_OFFSET_SCALE		5
@@ -453,6 +476,25 @@ static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg)
			? "NOM min voltage"
		: "none");

	rc = cpr3_read_fuse_param(base, msm8996_vdd_mx_ret_param,
				&fuse->vdd_mx_ret_fuse);
	if (rc) {
		cpr3_err(vreg, "Unable to read VDD_MX retention fuse, rc=%d\n",
			rc);
		return rc;
	}

	rc = cpr3_read_fuse_param(base, msm8996_vdd_apcc_ret_param,
				&fuse->vdd_apcc_ret_fuse);
	if (rc) {
		cpr3_err(vreg, "Unable to read VDD_APCC retention fuse, rc=%d\n",
			rc);
		return rc;
	}

	cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n",
		  fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse);

	id = vreg->thread->thread_id;

	for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) {
@@ -1227,6 +1269,107 @@ static int cpr3_hmss_init_thread(struct cpr3_thread *thread)
	return 0;
}

#define MAX_KVREG_NAME_SIZE 25
/**
 * cpr3_hmss_kvreg_init() - initialize HMSS Kryo Regulator data for a CPR3
 *		regulator
 * @vreg:		Pointer to the CPR3 regulator
 *
 * This function loads Kryo Regulator data from device tree if it is present
 * and requests a handle to the appropriate Kryo regulator device. In addition,
 * it initializes Kryo Regulator data originating from hardware fuses, such as
 * the LDO retention voltage, and requests the Kryo retention regulator to
 * be configured to that value.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_hmss_kvreg_init(struct cpr3_regulator *vreg)
{
	struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
	struct device_node *node = vreg->of_node;
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	int id = vreg->thread->thread_id;
	char kvreg_name_buf[MAX_KVREG_NAME_SIZE];
	int rc;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE,
		"vdd-thread%d-ldo-supply", id);

	if (!of_find_property(ctrl->dev->of_node, kvreg_name_buf , NULL))
		return 0;
	else if (!of_find_property(node, "qcom,ldo-headroom-voltage", NULL))
		return 0;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE, "vdd-thread%d-ldo", id);

	vreg->ldo_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
	if (IS_ERR(vreg->ldo_regulator)) {
		rc = PTR_ERR(vreg->ldo_regulator);
		if (rc != -EPROBE_DEFER)
			cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
				 kvreg_name_buf, rc);
		return rc;
	}

	vreg->ldo_regulator_bypass = BHS_MODE;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE, "vdd-thread%d-ldo-ret",
		  id);

	vreg->ldo_ret_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
	if (IS_ERR(vreg->ldo_ret_regulator)) {
		rc = PTR_ERR(vreg->ldo_ret_regulator);
		if (rc != -EPROBE_DEFER)
			cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
				 kvreg_name_buf, rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,ldo-headroom-voltage",
				&vreg->ldo_headroom_volt);
	if (rc) {
		cpr3_err(vreg, "error reading qcom,ldo-headroom-voltage, rc=%d\n",
			rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,ldo-max-voltage",
				&vreg->ldo_max_volt);
	if (rc) {
		cpr3_err(vreg, "error reading qcom,ldo-max-voltage, rc=%d\n",
			rc);
		return rc;
	}

	/* Determine the CPU retention voltage based on fused data */
	vreg->ldo_ret_volt =
		max(msm8996_vdd_apcc_fuse_ret_volt[fuse->vdd_apcc_ret_fuse],
		    msm8996_vdd_mx_fuse_ret_volt[fuse->vdd_mx_ret_fuse]);

	rc = regulator_set_voltage(vreg->ldo_ret_regulator, vreg->ldo_ret_volt,
				   INT_MAX);
	if (rc < 0) {
		cpr3_err(vreg, "regulator_set_voltage(ldo_ret) == %d failed, rc=%d\n",
			 vreg->ldo_ret_volt, rc);
		return rc;
	}

	/* optional properties, do not error out if missing */
	of_property_read_u32(node, "qcom,ldo-adjust-voltage",
			     &vreg->ldo_adjust_volt);

	vreg->ldo_mode_allowed = !of_property_read_bool(node,
							"qcom,ldo-disable");

	cpr3_info(vreg, "LDO headroom=%d uV, LDO adj=%d uV, LDO mode=%s, LDO retention=%d uV\n",
		  vreg->ldo_headroom_volt,
		  vreg->ldo_adjust_volt,
		  vreg->ldo_mode_allowed ? "allowed" : "disallowed",
		  vreg->ldo_ret_volt);

	return 0;
}

/**
 * cpr3_hmss_init_regulator() - perform all steps necessary to initialize the
 *		configuration data for a CPR3 regulator
@@ -1247,6 +1390,14 @@ static int cpr3_hmss_init_regulator(struct cpr3_regulator *vreg)
		return rc;
	}

	rc = cpr3_hmss_kvreg_init(vreg);
	if (rc) {
		if (rc != -EPROBE_DEFER)
			cpr3_err(vreg, "unable to initialize Kryo Regulator settings, rc=%d\n",
				 rc);
		return rc;
	}

	fuse = vreg->platform_fuses;
	if (fuse->limitation == MSM8996_CPR_LIMITATION_UNSUPPORTED) {
		cpr3_err(vreg, "this chip requires an unsupported voltage\n");
@@ -1367,89 +1518,6 @@ static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl)
	return 0;
}

#define MAX_KVREG_NAME_SIZE 25
/**
 * cpr3_hmss_kvreg_init() - initialize HMSS Kryo Regulator data for a CPR3
 *		regulator
 * @vreg:		Pointer to the CPR3 regulator
 *
 * This function loads Kryo Regulator data from device tree if it is present
 * and requests a handle to the appropriate Kryo regulator device.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_hmss_kvreg_init(struct cpr3_regulator *vreg)
{
	struct device_node *node = vreg->of_node;
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	int id = vreg->thread->thread_id;
	char kvreg_name_buf[MAX_KVREG_NAME_SIZE];
	int rc;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE,
		"vdd-thread%d-ldo-supply", id);

	if (!of_find_property(ctrl->dev->of_node, kvreg_name_buf , NULL))
		return 0;
	else if (!of_find_property(node, "qcom,ldo-headroom-voltage", NULL))
		return 0;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE, "vdd-thread%d-ldo", id);

	vreg->ldo_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
	if (IS_ERR(vreg->ldo_regulator)) {
		rc = PTR_ERR(vreg->ldo_regulator);
		if (rc != -EPROBE_DEFER)
			cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
				 kvreg_name_buf, rc);
		return rc;
	}

	vreg->ldo_regulator_bypass = BHS_MODE;

	scnprintf(kvreg_name_buf, MAX_KVREG_NAME_SIZE, "vdd-thread%d-ldo-ret",
		id);

	vreg->ldo_ret_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
	if (IS_ERR(vreg->ldo_ret_regulator)) {
		rc = PTR_ERR(vreg->ldo_ret_regulator);
		if (rc != -EPROBE_DEFER)
			cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
				 kvreg_name_buf, rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,ldo-headroom-voltage",
				&vreg->ldo_headroom_volt);
	if (rc) {
		cpr3_err(vreg, "error reading qcom,ldo-headroom-voltage, rc=%d\n",
			rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,ldo-max-voltage",
				&vreg->ldo_max_volt);
	if (rc) {
		cpr3_err(vreg, "error reading qcom,ldo-max-voltage, rc=%d\n",
			rc);
		return rc;
	}

	/* optional properties, do not error out if missing */
	of_property_read_u32(node, "qcom,ldo-adjust-voltage",
			     &vreg->ldo_adjust_volt);

	vreg->ldo_mode_allowed = !of_property_read_bool(node,
							  "qcom,ldo-disable");

	cpr3_info(vreg, "LDO headroom=%d uV, LDO adj=%d uV, LDO mode=%s\n",
		  vreg->ldo_headroom_volt,
		  vreg->ldo_adjust_volt,
		  vreg->ldo_mode_allowed ? "allowed" : "disallowed");

	return 0;
}

/**
 * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific
 *		initializations
@@ -1631,14 +1699,6 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev)
		for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
			vreg = &ctrl->thread[i].vreg[j];

			rc = cpr3_hmss_kvreg_init(vreg);
			if (rc) {
				if (rc != -EPROBE_DEFER)
					cpr3_err(vreg, "unable to initialize Kryo Regulator settings, rc=%d\n",
						 rc);
				return rc;
			}

			rc = cpr3_hmss_init_regulator(vreg);
			if (rc) {
				cpr3_err(vreg, "regulator initialization failed, rc=%d\n",
+4 −0
Original line number Diff line number Diff line
@@ -140,6 +140,9 @@ struct cpr3_corner {
 *			LDO operate
 * @ldo_adjust_volt:	Voltage in microvolts used to offset margin assigned
 *			to IR drop between PMIC and CPU
 * @ldo_ret_volt:	The lowest supported CPU retention voltage in
 *			microvolts. This voltage may vary part-to-part based
 *			upon the value of hardware fuses.
 * @ldo_max_volt:	The maximum physically supported LDO voltage in
 *			microvolts
 * @ldo_mode_allowed:	Boolean which indicates if LDO mode is allowed for this
@@ -177,6 +180,7 @@ struct cpr3_regulator {
	int			debug_corner;
	int			ldo_headroom_volt;
	int			ldo_adjust_volt;
	int			ldo_ret_volt;
	int			ldo_max_volt;
	bool			ldo_mode_allowed;
	bool			vreg_enabled;