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

Commit 1c101d07 authored by Tirupathi Reddy's avatar Tirupathi Reddy
Browse files

regulator: cpr3: add support for CPR4-compliant controllers



Augment the cpr3-regulator driver to support CPR4-compliant controllers.
Also, introduce the cpr4-apss-regulator driver to handle CPU subsystem
specific power requirements for msmtitanium chips.

Change-Id: I8e6535542ba8f86d7c4893370e3fb1c934456838
Signed-off-by: default avatarTirupathi Reddy <tirupath@codeaurora.org>
parent 3cb14278
Loading
Loading
Loading
Loading
+258 −0
Original line number Diff line number Diff line
Qualcomm Technologies, Inc. CPR4 Regulator - APSS Specific Bindings

APSS CPR4 controllers each support one CPR thread that monitors the voltage of
a pair of application processor (APSS) clusters that are powered by a shared
regulator supply. They also have a hardware channel to use these requests to
directly change the supply voltage at the PMIC via the SPM without software
intervention.

APSS CPR4 controllers also have to take into account the state of the memory
array power mux (APM) when scaling voltage to ensure that memory always receives
a sufficiently high voltage.

Both CPR open-loop voltages and CPR target quotients are stored in hardware
fuses for APSS CPR4 controllers.

This document describes the APSS specific CPR4 bindings.

=======================
Required Node Structure
=======================

CPR4 regulators must be described in three levels of devices nodes.  The first
level describes the CPR4 controller.  The second level describes one or more
hardware threads managed by the controller.  The third level describes one or
more logical regulators handled by each CPR thread.

All platform independent cpr3-regulator binding guidelines defined in
cpr3-regulator.txt also apply to cpr4-apss-regulator devices.

====================================
First Level Nodes - CPR4 Controllers
====================================

APSS specific properties:
- compatible
	Usage:      required
	Value type: <string>
	Definition: should be one of the following:
		    "qcom,cpr4-msmtitanium-apss-regulator";

- interrupts
	Usage:      required
	Value type: <prop-encoded-array>
	Definition: CPR interrupt specifier and a hardware closed-loop ceiling
		    interrupt specifier.

- interrupt-names
	Usage:      required
	Value type: <stringlist>
	Definition: Interrupt names.  This list must match up 1-to-1 with the
		    interrupts specified in the 'interrupts' property. "cpr"
		    and "ceiling" must be specified.

- qcom,apm-ctrl
	Usage:      required on systems that need APM management
	Value type: <phandle>
	Definition: phandle of memory array power mux (APM) controller device
		    node for the APM that is used by the APSS VDD supply

- qcom,apm-threshold-voltage
	Usage:      required if qcom,apm-ctrl is specified
	Value type: <u32>
	Definition: Specifies the APM threshold voltage in microvolts.  If the
		    vdd-supply voltage is greater than or equal to this level,
		    then the APM is switched to use the vdd-supply. If the
		    vdd-supply voltage is below this level, then the APM is
		    switched to use the system-supply.

- qcom,apm-hysteresis-voltage
	Usage:      optional
	Value type: <u32>
	Definition: Specifies the voltage delta in microvolts between the APM
		    threshold voltage and the highest corner open-loop voltage
		    which may be used as the ceiling for the corner.  If this
		    property is not specified, then a value of 0 is assumed.

- qcom,cpr-hw-closed-loop
	Usage:      optional
	Value type: <empty>
	Definition: Boolean flag which indicates that the APSS CPR4 controller
		    should operate in hardware closed-loop mode as opposed to
		    software closed-loop mode.

- vdd-limit-supply
	Usage:      required
	Value type: <phandle>
	Definition: phandle of the VDD supply limit regulator which controls the
		    CPR ceiling and floor voltages when operating in hardware
		    closed-loop mode.

- qcom,cpr-down-error-step-limit
	Usage:      required
	Value type: <u32>
	Definition: CPR4 hardware closed-loop down error step limit which
		    defines the maximum number of vdd-supply regulator steps
		    that the voltage may be reduced as the result of a single
		    CPR measurement.

- qcom,cpr-up-error-step-limit
	Usage:      required
	Value type: <u32>
	Definition: CPR4 hardware closed-loop up error step limit which defines
		    the maximum number of vdd-supply regulator steps that the
                    voltage may be increased as the result of a single
		    CPR measurement.

- qcom,cpr-saw-use-unit-mV
	Usage:      optional
	Value type: <empty>
	Definition: Boolean flag which indicates that the unit used in SAW PVC
		    interface is mV. Use this for vdd-supply regulators which
		    do not use PMIC voltage control register LSBs per actually
		    unique PMIC regulator output voltage.

=================================================
Second Level Nodes - CPR Threads for a Controller
=================================================

APSS specific properties:
N/A

===============================================
Third Level Nodes - CPR Regulators for a Thread
===============================================

APSS specific properties:
- qcom,cpr-fuse-corners
	Usage:      required
	Value type: <u32>
	Definition: Specifies the number of fuse corners. This value must be 4
		    for APSS. These fuse corners are: LowSVS, SVS, Nominal,
		    and Turbo.

- qcom,cpr-fuse-combos
	Usage:      required
	Value type: <u32>
	Definition: Specifies the number of fuse combinations being supported by
		    the device.  This value is utilized by several other
		    properties.  Supported values are 1 up to the maximum
		    possible for a given regulator type.  For APSS the maximum
		    supported value is 64.  The first 8 fuse combos correspond
		    to speed bin fuse value 0 along with CPR revision fuse
		    values 0 to 7.  The second 8 fuse combos correspond to speed
		    bin fuse value 1 along with CPR revision fuse values 0 to 7.
		    The last 8 fuse combos correspond to speed bin fuse value 7
		    along with CPR revision fuse values 0 to 7.

- qcom,cpr-speed-bins
	Usage:      optional
	Value type: <u32>
	Definition: Specifies the number of speed bins being supported by the
		    device.  This value is utilized by several other properties.
		    Supported values are 1 up to the maximum possible for a
		    given regulator type.  For APSS the maximum supported value
		    is 8.

- qcom,mem-acc-voltage
	Usage:      required if mem-acc-supply is specified for the CPR4 controller
		    containing this regulator
	Value type: <prop-encoded-array>
	Definition: A list of integer tuples which each define the mem-acc-supply
		    corner for each voltage corner in order from lowest to highest.

		    The list must contain qcom,cpr-fuse-combos number of tuples
		    in which case the tuples are matched to fuse combinations
		    1-to-1 or qcom,cpr-speed-bins number of tuples in which case
		    the tuples are matched to speed bins 1-to-1 or exactly 1
		    tuple which is used regardless of the fuse combination and
		    speed bin found on a given chip.

		    Each tuple must be of the length defined in the
		    corresponding element of the qcom,cpr-corners property or
		    the qcom,cpr-speed-bins property.  A single tuple may only
		    be specified if all of the corner counts in qcom,cpr-corners
		    are the same.

- qcom,allow-quotient-interpolation
	Usage:      optional
	Value type: <empty>
	Definition: Boolean flag which indicates that it is acceptable to use
		    interpolated CPR target quotient values.  These values are
		    interpolated between the target quotient Fmax fuse values.

=======
Example
=======

apc_cpr: cpr4-ctrl@b018000 {
	compatible = "qcom,cpr4-msmtitanium-apss-regulator";
	reg = <0xb018000 0x4000>, <0xa4000 0x1000>;
	reg-names = "cpr_ctrl", "fuse_base";
	interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>,
		<GIC_SPI 282 IRQ_TYPE_EDGE_RISING>;
	interrupt-names = "cpr", "ceiling";

	qcom,cpr-ctrl-name = "apc";

	qcom,cpr-sensor-time = <1000>;
	qcom,cpr-loop-time = <5000000>;
	qcom,cpr-idle-cycles = <15>;
	qcom,cpr-step-quot-init-min = <13>;
	qcom,cpr-step-quot-init-max = <13>;
	qcom,cpr-count-mode = <2>;		/* Staggered */
	qcom,cpr-down-error-step-limit = <1>;
	qcom,cpr-up-error-step-limit = <1>;

	qcom,apm-ctrl = <&apc_apm>;
	qcom,apm-threshold-voltage = <848000>;
	qcom,apm-hysteresis-voltage = <5000>;

	vdd-supply = <&pmtitanium_s5>;
	qcom,voltage-step = <5000>;
	vdd-limit-supply = <&pmtitanium_s5_limit>;
	mem-acc-supply = <&apc_mem_acc_vreg>;

	qcom,cpr-enable;
	qcom,cpr-hw-closed-loop;

	thread@0 {
		qcom,cpr-thread-id = <0>;
		qcom,cpr-consecutive-up = <1>;
		qcom,cpr-consecutive-down = <1>;
		qcom,cpr-up-threshold = <1>;
		qcom,cpr-down-threshold = <1>;

		apc_vreg: regulator {
			regulator-name = "apc_corner";
			regulator-min-microvolt = <1>;
			regulator-max-microvolt = <8>;

			qcom,cpr-fuse-corners = <4>;
			qcom,cpr-fuse-combos = <8>;
			qcom,cpr-speed-bins = <1>;
			qcom,cpr-corners = <8>;

			qcom,cpr-corner-fmax-map = <1 2 4 8>;

			qcom,cpr-voltage-ceiling =
				<645000  720000 790000  865000 920000
				 990000 1065000 1065000>;

			qcom,cpr-voltage-floor =
				<590000  625000 690000  755000 800000
				 855000  920000 920000>;

			qcom,mem-acc-voltage = <1 1 2 2 2 2 2 2>;

			qcom,corner-frequencies =
				<652800000 1036800000 1401600000
				1689600000 1843200000 1958400000
				2150400000 2208000000>;

			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;
		};
	};
};
+14 −0
Original line number Diff line number Diff line
@@ -853,6 +853,20 @@ config REGULATOR_CPR3_MMSS
	  initial voltage values out of hardware fuses and CPR target quotient
	  values out of device tree.

config REGULATOR_CPR4_APSS
	bool "CPR4 regulator for APSS"
	depends on OF
	select REGULATOR_CPR3
	help
	  This driver supports Qualcomm Technologies, Inc. APSS application
	  processor specific features including memory array power mux (APM)
	  switching, one CPR4 thread which monitor the two APSS clusters that
	  are both powered by a shared supply, hardware closed-loop auto
	  voltage stepping, voltage adjustments based on online core count,
	  voltage adjustments based on temperature readings, and voltage
	  adjustments for performance boost mode. This driver reads both initial
	  voltage and CPR target quotient values out of hardware fuses.

config REGULATOR_KRYO
	bool "Kryo regulator driver"
	depends on OF
+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ obj-$(CONFIG_REGULATOR_CPR) += cpr-regulator.o
obj-$(CONFIG_REGULATOR_CPR3) += cpr3-regulator.o cpr3-util.o
obj-$(CONFIG_REGULATOR_CPR3_HMSS) += cpr3-hmss-regulator.o
obj-$(CONFIG_REGULATOR_CPR3_MMSS) += cpr3-mmss-regulator.o
obj-$(CONFIG_REGULATOR_CPR4_APSS) += cpr4-apss-regulator.o
obj-$(CONFIG_REGULATOR_QPNP_LABIBB) += qpnp-labibb-regulator.o
obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o
obj-$(CONFIG_REGULATOR_KRYO) += kryo-regulator.o
+4 −137
Original line number Diff line number Diff line
@@ -753,91 +753,6 @@ done:
	return rc;
}

/**
 * cpr3_hmss_parse_closed_loop_voltage_adjustments() - load per-fuse-corner and
 *		per-corner closed-loop adjustment values from device tree
 * @vreg:		Pointer to the CPR3 regulator
 * @volt_adjust:	Pointer to array which will be filled with the
 *			per-corner closed-loop adjustment voltages
 * @volt_adjust_fuse:	Pointer to array which will be filled with the
 *			per-fuse-corner closed-loop adjustment voltages
 * @ro_scale:		Pointer to array which will be filled with the
 *			per-fuse-corner RO scaling factor values with units of
 *			QUOT/V
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_hmss_parse_closed_loop_voltage_adjustments(
			struct cpr3_regulator *vreg, int *volt_adjust,
			int *volt_adjust_fuse, int *ro_scale)
{
	struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
	int i, rc;
	u32 *ro_all_scale;

	if (!of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)
	    && !of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)
	    && !vreg->aging_allowed) {
		/* No adjustment required. */
		return 0;
	} else if (!of_find_property(vreg->of_node,
			"qcom,cpr-ro-scaling-factor", NULL)) {
		cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
		return -EINVAL;
	}

	ro_all_scale = kcalloc(vreg->fuse_corner_count * CPR3_RO_COUNT,
				sizeof(*ro_all_scale), GFP_KERNEL);
	if (!ro_all_scale)
		return -ENOMEM;

	rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor",
		vreg->fuse_corner_count * CPR3_RO_COUNT, ro_all_scale);
	if (rc) {
		cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
			rc);
		goto done;
	}

	for (i = 0; i < vreg->fuse_corner_count; i++)
		ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]];

	for (i = 0; i < vreg->corner_count; i++)
		memcpy(vreg->corner[i].ro_scale,
		 &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT],
		 sizeof(*ro_all_scale) * CPR3_RO_COUNT);

	if (of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
		rc = cpr3_parse_array_property(vreg,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment",
			vreg->fuse_corner_count, volt_adjust_fuse);
		if (rc) {
			cpr3_err(vreg, "could not load closed-loop fused voltage adjustments, rc=%d\n",
				rc);
			goto done;
		}
	}

	if (of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)) {
		rc = cpr3_parse_corner_array_property(vreg,
			"qcom,cpr-closed-loop-voltage-adjustment",
			1, volt_adjust);
		if (rc) {
			cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
				rc);
			goto done;
		}
	}

done:
	kfree(ro_all_scale);
	return rc;
}

/**
 * cpr3_msm8996_hmss_set_no_interpolation_quotients() - use the fused target
 *		quotient values for lower frequencies.
@@ -942,8 +857,8 @@ static int cpr3_msm8996_hmss_calculate_target_quotients(
		goto done;
	}

	rc = cpr3_hmss_parse_closed_loop_voltage_adjustments(vreg, volt_adjust,
			volt_adjust_fuse, ro_scale);
	rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
				volt_adjust, volt_adjust_fuse, ro_scale);
	if (rc) {
		cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
			rc);
@@ -1481,55 +1396,6 @@ static int cpr3_hmss_init_regulator(struct cpr3_regulator *vreg)
	return 0;
}

/**
 * cpr3_hmss_apm_init() - initialize HMSS APM data for a CPR3 controller
 * @ctrl:		Pointer to the CPR3 controller
 *
 * This function loads HMSS memory array power mux (APM) data from device tree
 * if it is present and requests a handle to the appropriate APM controller
 * device.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl)
{
	struct device_node *node = ctrl->dev->of_node;
	int rc;

	if (!of_find_property(node, "qcom,apm-ctrl", NULL)) {
		/* No APM used */
		return 0;
	}

	ctrl->apm = msm_apm_ctrl_dev_get(ctrl->dev);
	if (IS_ERR(ctrl->apm)) {
		rc = PTR_ERR(ctrl->apm);
		if (rc != -EPROBE_DEFER)
			cpr3_err(ctrl, "APM get failed, rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,apm-threshold-voltage",
				&ctrl->apm_threshold_volt);
	if (rc) {
		cpr3_err(ctrl, "error reading qcom,apm-threshold-voltage, rc=%d\n",
			rc);
		return rc;
	}
	ctrl->apm_threshold_volt
		= CPR3_ROUND(ctrl->apm_threshold_volt, ctrl->step_volt);

	/* No error check since this is an optional property. */
	of_property_read_u32(node, "qcom,apm-hysteresis-voltage",
				&ctrl->apm_adj_volt);
	ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);

	ctrl->apm_high_supply = MSM_APM_SUPPLY_APCC;
	ctrl->apm_low_supply = MSM_APM_SUPPLY_MX;

	return 0;
}

/**
 * cpr3_hmss_init_aging() - perform HMSS CPR3 controller specific
 *		aging initializations
@@ -1641,7 +1507,7 @@ static int cpr3_hmss_init_controller(struct cpr3_controller *ctrl)
	of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-clock-throttling",
			&ctrl->proc_clock_throttle);

	rc = cpr3_hmss_apm_init(ctrl);
	rc = cpr3_apm_init(ctrl);
	if (rc) {
		if (rc != -EPROBE_DEFER)
			cpr3_err(ctrl, "unable to initialize APM settings, rc=%d\n",
@@ -1665,6 +1531,7 @@ static int cpr3_hmss_init_controller(struct cpr3_controller *ctrl)
		ctrl->sensor_owner[i] = 1;

	ctrl->cpr_clock_rate = MSM8996_HMSS_CPR_CLOCK_RATE;
	ctrl->ctrl_type = CPR_CTRL_TYPE_CPR3;
	ctrl->supports_hw_closed_loop = true;
	ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
						"qcom,cpr-hw-closed-loop");
+2 −36
Original line number Diff line number Diff line
@@ -845,41 +845,6 @@ static int cpr3_mmss_init_thread(struct cpr3_thread *thread)
	return 0;
}

/**
 * cpr3_mmss_init_mem_acc() - perform MMSS CPR3 controller specific
 *		mem-acc regulator initializations
 * @ctrl:		Pointer to the CPR3 controller
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_mmss_init_mem_acc(struct cpr3_controller *ctrl)
{
	struct cpr3_regulator *vreg = &ctrl->thread[0].vreg[0];
	u32 *temp;
	int i, rc;

	if (!ctrl->mem_acc_regulator) {
		cpr3_info(ctrl, "not using memory accelerator regulator\n");
		return 0;
	}

	temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
	if (!temp)
		return -ENOMEM;

	rc = cpr3_parse_corner_array_property(vreg, "qcom,mem-acc-voltage",
					      1, temp);
	if (rc) {
		cpr3_err(ctrl, "could not load mem-acc corners, rc=%d\n", rc);
	} else {
		for (i = 0; i < vreg->corner_count; i++)
			vreg->corner[i].mem_acc_volt = temp[i];
	}

	kfree(temp);
	return rc;
}

/**
 * cpr3_mmss_init_controller() - perform MMSS CPR3 controller specific
 *		initializations
@@ -911,6 +876,7 @@ static int cpr3_mmss_init_controller(struct cpr3_controller *ctrl)
		return -ENOMEM;

	ctrl->cpr_clock_rate = MSM8996_MMSS_CPR_CLOCK_RATE;
	ctrl->ctrl_type = CPR_CTRL_TYPE_CPR3;

	ctrl->iface_clk = devm_clk_get(ctrl->dev, "iface_clk");
	if (IS_ERR(ctrl->iface_clk)) {
@@ -1018,7 +984,7 @@ static int cpr3_mmss_regulator_probe(struct platform_device *pdev)
		return rc;
	}

	rc = cpr3_mmss_init_mem_acc(ctrl);
	rc = cpr3_mem_acc_init(&ctrl->thread[0].vreg[0]);
	if (rc) {
		cpr3_err(ctrl, "failed to initialize mem-acc configuration, rc=%d\n",
			 rc);
Loading