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

Commit 1a9d62db authored by David Collins's avatar David Collins Committed by Osvaldo Banuelos
Browse files

regulator: cprh-regulator: add support for MEM ACC threshold voltage



Add support for configuring the memory accelerator (MEM ACC)
threshold voltage and the MEM ACC crossover voltage.
The threshold voltage is used to restrict the floor to ceiling
voltage range of all corners so that they cannot cross the
the MEM ACC threshold voltage due to CPR operation.  The
crossover voltage is set when switching the MEM ACC
configuration.

If specified, the APM and MEM ACC crossover voltages are added
to the array of corners after all true corners.  If both are
specified, then the APM crossover corner is added before the MEM
ACC crossover corner (i.e. last corner = MEM ACC crossover and
second to last corner = APM crossover).

CRs-Fixed: 1088429
Change-Id: I2b9b746071579ba9d4bcdcfb6cb755ca08a73182
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent fcb69346
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -73,6 +73,24 @@ KBSS specific properties:
		    switching. If this property is not specified, then a value
		    of 0 is assumed.

- qcom,mem-acc-threshold-voltage
	Usage:      optional
	Value type: <u32>
	Definition: Specifies the highest memory accelerator (MEM ACC) threshold
		    voltage in microvolts.  The floor to ceiling voltage range
		    for every corner is adjusted to ensure that it does not
		    intersect this voltage. The value of this property must
		    match with the MEM ACC threshold voltage defined in the OSM
		    device to ensure that MEM ACC settings are switched
		    appropriately.

- qcom,mem-acc-crossover-voltage
	Usage:      required if qcom,mem-acc-threshold-voltage is specified
	Value type: <u32>
	Definition: Specifies the MEM ACC crossover voltage in microvolts which
		    corresponds to the voltage the VDD supply must be set to
		    when switching the MEM ACC configuration.

- qcom,voltage-base
	Usage:      required
	Value type: <u32>
+11 −0
Original line number Diff line number Diff line
@@ -565,6 +565,11 @@ struct cpr3_panic_regs_info {
 * @mem_acc_corner_map: mem-acc regulator corners mapping to low and high
 *			voltage mem-acc settings for the memories powered by
 *			this CPR3 controller and its associated CPR3 regulators
 * @mem_acc_crossover_volt: Voltage in microvolts corresponding to the voltage
 *			that the VDD supply must be set to while a MEM ACC
 *			switch is in progress. This element must be initialized
 *			for CPRh controllers when a MEM ACC threshold voltage is
 *			defined.
 * @core_clk:		Pointer to the CPR3 controller core clock
 * @iface_clk:		Pointer to the CPR3 interface clock (platform specific)
 * @bus_clk:		Pointer to the CPR3 bus clock (platform specific)
@@ -744,6 +749,7 @@ struct cpr3_controller {
	int			system_supply_max_volt;
	int			mem_acc_threshold_volt;
	int			mem_acc_corner_map[CPR3_MEM_ACC_CORNERS];
	int			mem_acc_crossover_volt;
	struct clk		*core_clk;
	struct clk		*iface_clk;
	struct clk		*bus_clk;
@@ -876,6 +882,7 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
int cpr3_apm_init(struct cpr3_controller *ctrl);
int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg);

#else

@@ -1052,6 +1059,10 @@ static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
{
}

static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
{
}

#endif /* CONFIG_REGULATOR_CPR3 */

#endif /* __REGULATOR_CPR_REGULATOR_H__ */
+67 −3
Original line number Diff line number Diff line
@@ -680,12 +680,13 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
	}

	/*
	 * In CPRh compliant controllers an additional corner is
	 * allocated to correspond to the APM crossover voltage
	 * For CPRh compliant controllers two additional corners are
	 * allocated to correspond to the APM crossover voltage and the MEM ACC
	 * crossover voltage.
	 */
	vreg->corner = devm_kcalloc(ctrl->dev, ctrl->ctrl_type ==
				    CPR_CTRL_TYPE_CPRH ?
				    vreg->corner_count + 1 :
				    vreg->corner_count + 2 :
				    vreg->corner_count,
				    sizeof(*vreg->corner), GFP_KERNEL);
	temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
@@ -2083,3 +2084,66 @@ void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
				corner->ceiling_volt, corner->open_loop_volt);
	}
}

/**
 * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling
 *		voltages so that they do not intersect the MEM ACC threshold
 *		voltage
 * @vreg:		Pointer to the CPR3 regulator
 *
 * The following algorithm is applied:
 *	if floor < threshold <= ceiling:
 *		if open_loop >= threshold, then floor = threshold
 *		else ceiling = threshold - step
 * where:
 *	step = voltage in microvolts of a single step of the VDD supply
 *
 * The open-loop voltage is also bounded by the new floor or ceiling value as
 * needed.
 *
 * Return: none
 */
void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	struct cpr3_corner *corner;
	int i, threshold, prev_ceiling, prev_floor, prev_open_loop;

	if (!ctrl->mem_acc_threshold_volt) {
		/* MEM ACC not being used. */
		return;
	}

	ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt,
						ctrl->step_volt);

	threshold = ctrl->mem_acc_threshold_volt;

	for (i = 0; i < vreg->corner_count; i++) {
		corner = &vreg->corner[i];

		if (threshold <= corner->floor_volt
		    || threshold > corner->ceiling_volt)
			continue;

		prev_floor = corner->floor_volt;
		prev_ceiling = corner->ceiling_volt;
		prev_open_loop = corner->open_loop_volt;

		if (corner->open_loop_volt >= threshold) {
			corner->floor_volt = max(corner->floor_volt, threshold);
			if (corner->open_loop_volt < corner->floor_volt)
				corner->open_loop_volt = corner->floor_volt;
		} else {
			corner->ceiling_volt = threshold - ctrl->step_volt;
		}

		if (corner->floor_volt != prev_floor
		    || corner->ceiling_volt != prev_ceiling
		    || corner->open_loop_volt != prev_open_loop)
			cpr3_debug(vreg, "MEM ACC threshold=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
				threshold, i, prev_floor, prev_ceiling,
				prev_open_loop, corner->floor_volt,
				corner->ceiling_volt, corner->open_loop_volt);
	}
}
+73 −0
Original line number Diff line number Diff line
@@ -867,6 +867,44 @@ static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
	return 0;
}

/**
 * cprh_kbss_mem_acc_crossover_as_corner() - introduce a corner whose floor,
 *		open-loop, and ceiling voltages correspond to the MEM ACC
 *		crossover voltage.
 * @vreg:		Pointer to the CPR3 regulator
 *
 * The MEM ACC corner is utilized as a crossover corner by OSM and CPRh
 * hardware to set the VDD supply voltage during the MEM ACC switch
 * routine.
 *
 * Return: 0 on success, errno on failure
 */
static int cprh_kbss_mem_acc_crossover_as_corner(struct cpr3_regulator *vreg)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	struct cpr3_corner *corner;

	if (!ctrl->mem_acc_crossover_volt) {
		/* MEM ACC voltage crossover corner not required. */
		return 0;
	}

	corner = &vreg->corner[vreg->corner_count];
	/*
	 * 0 MHz indicates this corner is not to be
	 * used as active DCVS set point.
	 */
	corner->proc_freq = 0;
	corner->floor_volt = ctrl->mem_acc_crossover_volt;
	corner->ceiling_volt = ctrl->mem_acc_crossover_volt;
	corner->open_loop_volt = ctrl->mem_acc_crossover_volt;
	corner->abs_ceiling_volt = ctrl->mem_acc_crossover_volt;
	corner->use_open_loop = true;
	vreg->corner_count++;

	return 0;
}

/**
 * cprh_msm8998_kbss_set_no_interpolation_quotients() - use the fused target
 *		quotient values for lower frequencies.
@@ -1198,6 +1236,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
	}

	cprh_adjust_voltages_for_apm(vreg);
	cprh_adjust_voltages_for_mem_acc(vreg);

	cpr3_open_loop_voltage_as_ceiling(vreg);

@@ -1250,6 +1289,13 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
		return rc;
	}

	rc = cprh_kbss_mem_acc_crossover_as_corner(vreg);
	if (rc) {
		cpr3_err(vreg, "unable to introduce MEM ACC voltage crossover corner, rc=%d\n",
			rc);
		return rc;
	}

	cprh_kbss_print_settings(vreg);

	return 0;
@@ -1422,6 +1468,25 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
	ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
					"qcom,cpr-saw-use-unit-mV");

	rc = of_property_read_u32(ctrl->dev->of_node,
				  "qcom,mem-acc-threshold-voltage",
				  &ctrl->mem_acc_threshold_volt);
	if (!rc) {
		ctrl->mem_acc_threshold_volt
		    = CPR3_ROUND(ctrl->mem_acc_threshold_volt, ctrl->step_volt);

		rc = of_property_read_u32(ctrl->dev->of_node,
					  "qcom,mem-acc-crossover-voltage",
					  &ctrl->mem_acc_crossover_volt);
		if (rc) {
			cpr3_err(ctrl, "error reading property qcom,mem-acc-crossover-voltage, rc=%d\n",
				 rc);
			return rc;
		}
		ctrl->mem_acc_crossover_volt
		    = CPR3_ROUND(ctrl->mem_acc_crossover_volt, ctrl->step_volt);
	}

	/*
	 * Use fixed step quotient if specified otherwise use dynamically
	 * calculated per RO step quotient
@@ -1477,6 +1542,14 @@ static int cprh_kbss_populate_opp_table(struct cpr3_controller *ctrl)

	for (i = 0; i < vreg->corner_count; i++) {
		corner = &vreg->corner[i];
		if (!corner->proc_freq) {
			/*
			 * 0 MHz indicates this corner is not to be
			 * used as active DCVS set point. Don't add it
			 * to the OPP table.
			 */
			continue;
		}
		rc = dev_pm_opp_add(dev, corner->proc_freq, i + 1);
		if (rc) {
			cpr3_err(ctrl, "could not add OPP for corner %d with frequency %u MHz, rc=%d\n",