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

Commit b7e53064 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "regulator: cpr3: support LDO handling for different LDO types"

parents a204fcac 23603a7d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/kryo-regulator.h>
#include <linux/regulator/msm-ldo-regulator.h>

#include "cpr3-regulator.h"

+186 −38
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/kryo-regulator.h>
#include <linux/regulator/msm-ldo-regulator.h>

#include <soc/qcom/spm.h>

@@ -1761,7 +1761,12 @@ static int cpr3_regulator_config_ldo_retention(struct cpr3_regulator *vreg,
{
	struct regulator *ldo_ret_reg = vreg->ldo_ret_regulator;
	int retention_volt, rc;
	enum kryo_supply_mode mode;
	enum msm_ldo_supply_mode mode;

	if (!ldo_ret_reg) {
		/* LDO retention regulator is not defined */
		return 0;
	}

	retention_volt = regulator_get_voltage(ldo_ret_reg);
	if (retention_volt < 0) {
@@ -1783,8 +1788,8 @@ static int cpr3_regulator_config_ldo_retention(struct cpr3_regulator *vreg,
}

/**
 * cpr3_regulator_config_ldo_mem_acc() - configure the mem-acc regulator
 *		corner based upon a future LDO regulator voltage setpoint
 * cpr3_regulator_config_kryo_ldo_mem_acc() - configure the mem-acc regulator
 *		corner based upon a future Kryo LDO regulator voltage setpoint
 * @vreg:		Pointer to the CPR3 regulator
 * @new_volt:		New voltage in microvolts that the LDO regulator needs
 *			to end up at
@@ -1796,7 +1801,7 @@ static int cpr3_regulator_config_ldo_retention(struct cpr3_regulator *vreg,
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_regulator_config_ldo_mem_acc(struct cpr3_regulator *vreg,
static int cpr3_regulator_config_kryo_ldo_mem_acc(struct cpr3_regulator *vreg,
					     int new_volt)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
@@ -1858,18 +1863,21 @@ static int cpr3_regulator_config_ldo_mem_acc(struct cpr3_regulator *vreg,
}

/**
 * cpr3_regulator_set_bhs_mode() - configure the LDO regulator associated with
 *		a CPR3 regulator to BHS mode
 * cpr3_regulator_kryo_bhs_prepare() - configure the Kryo LDO regulator
 *		associated with a CPR3 regulator in preparation for BHS
 *		mode switch.
 * @vreg:		Pointer to the CPR3 regulator
 * @vdd_volt:		Last known settled voltage in microvolts for the VDD
 *			supply
 * @vdd_ceiling_volt:	Last known aggregated ceiling voltage in microvolts for
 *			the VDD supply
 *
 * This function performs the necessary steps to switch an LDO regulator
 * to BHS mode (LDO bypassed mode).
 * This function performs the necessary steps prior to switching a Kryo LDO
 * regulator to BHS mode (LDO bypassed mode).
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_regulator_set_bhs_mode(struct cpr3_regulator *vreg,
static int cpr3_regulator_kryo_bhs_prepare(struct cpr3_regulator *vreg,
			       int vdd_volt, int vdd_ceiling_volt)
{
	struct regulator *ldo_reg = vreg->ldo_regulator;
@@ -1882,7 +1890,7 @@ static int cpr3_regulator_set_bhs_mode(struct cpr3_regulator *vreg,
		bhs_volt = vreg->ldo_max_volt;
	}

	rc = cpr3_regulator_config_ldo_mem_acc(vreg, bhs_volt);
	rc = cpr3_regulator_config_kryo_ldo_mem_acc(vreg, bhs_volt);
	if (rc) {
		cpr3_err(vreg, "failed to configure mem-acc settings\n");
		return rc;
@@ -1896,9 +1904,40 @@ static int cpr3_regulator_set_bhs_mode(struct cpr3_regulator *vreg,
		return rc;
	}

	return rc;
}

/**
 * cpr3_regulator_set_bhs_mode() - configure the LDO regulator associated with
 *		a CPR3 regulator to BHS mode
 * @vreg:		Pointer to the CPR3 regulator
 * @vdd_volt:		Last known settled voltage in microvolts for the VDD
 *			supply
 * @vdd_ceiling_volt:	Last known aggregated ceiling voltage in microvolts for
 *			the VDD supply
 *
 * This function performs the necessary steps to switch an LDO regulator
 * to BHS mode (LDO bypassed mode).
 */
static int cpr3_regulator_set_bhs_mode(struct cpr3_regulator *vreg,
			       int vdd_volt, int vdd_ceiling_volt)
{
	struct regulator *ldo_reg = vreg->ldo_regulator;
	int rc;

	if (vreg->ldo_type == CPR3_LDO_KRYO) {
		rc = cpr3_regulator_kryo_bhs_prepare(vreg, vdd_volt,
				vdd_ceiling_volt);
		if (rc) {
			cpr3_err(vreg, "cpr3 regulator bhs mode prepare failed, rc=%d\n",
				rc);
			return rc;
		}
	}

	rc = regulator_allow_bypass(ldo_reg, BHS_MODE);
	if (rc) {
		cpr3_err(vreg, "regulator_allow_bypass(ldo) == %s failed, rc=%d\n",
		cpr3_err(vreg, "regulator_allow_bypass(bhs) == %s failed, rc=%d\n",
			 BHS_MODE ? "true" : "false", rc);
		return rc;
	}
@@ -2009,44 +2048,34 @@ static int cpr3_regulator_ldo_apm_prepare(struct cpr3_controller *ctrl,
}

/**
 * cpr3_regulator_config_vreg_ldo() - configure the voltage and bypass state for
 *		the LDO regulator associated with a single CPR3 regulator.
 * cpr3_regulator_config_vreg_kryo_ldo() - configure the voltage and bypass
 *		state for the Kryo LDO regulator associated with a single CPR3
 *		regulator.
 *
 * @vreg:		Pointer to the CPR3 regulator
 * @vdd_floor_volt:	Last known aggregated floor voltage in microvolts for
 *			the VDD supply
 * @vdd_ceiling_volt:	Last known aggregated ceiling voltage in microvolts for
 *			the VDD supply
 * @new_volt:		New voltage in microvolts that VDD supply needs to
 *			end up at
 * @ref_volt:		Reference voltage in microvolts corresponds either to
 *			the aggregated floor voltage or the next VDD supply
 *			setpoint.
 * @last_volt:		Last known voltage in microvolts for the VDD supply
 *
 * This function performs all relevant LDO or BHS configurations if an LDO
 * This function performs all relevant LDO or BHS configurations if a Kryo LDO
 * regulator is specified.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_regulator_config_vreg_ldo(struct cpr3_regulator *vreg,
static int cpr3_regulator_config_vreg_kryo_ldo(struct cpr3_regulator *vreg,
			  int vdd_floor_volt, int vdd_ceiling_volt,
			  int new_volt, int last_volt)
			  int ref_volt, int last_volt)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	struct regulator *ldo_reg = vreg->ldo_regulator;
	struct cpr3_corner *current_corner;
	enum msm_apm_supply apm_mode;
	int rc, ldo_volt, final_ldo_volt, bhs_volt, max_volt, safe_volt;
	int ref_volt;

	ref_volt = ctrl->use_hw_closed_loop ? vdd_floor_volt :
		new_volt;

	rc = cpr3_regulator_config_ldo_retention(vreg, ref_volt);
	if (rc)
		return rc;

	if (!vreg->vreg_enabled || vreg->current_corner
	    == CPR3_REGULATOR_CORNER_INVALID)
		return 0;

	current_corner = &vreg->corner[vreg->current_corner];
	ldo_volt = current_corner->open_loop_volt
@@ -2087,7 +2116,7 @@ static int cpr3_regulator_config_vreg_ldo(struct cpr3_regulator *vreg,
						bhs_volt),
					    vreg->ldo_max_volt);

			rc = cpr3_regulator_config_ldo_mem_acc(vreg,
			rc = cpr3_regulator_config_kryo_ldo_mem_acc(vreg,
							       safe_volt);
			if (rc) {
				cpr3_err(vreg, "failed to configure mem-acc settings\n");
@@ -2119,7 +2148,7 @@ static int cpr3_regulator_config_vreg_ldo(struct cpr3_regulator *vreg,
		else
			final_ldo_volt = ldo_volt;

		rc = cpr3_regulator_config_ldo_mem_acc(vreg,
		rc = cpr3_regulator_config_kryo_ldo_mem_acc(vreg,
						       final_ldo_volt);
		if (rc) {
			cpr3_err(vreg, "failed to configure mem-acc settings\n");
@@ -2145,6 +2174,115 @@ static int cpr3_regulator_config_vreg_ldo(struct cpr3_regulator *vreg,
	return 0;
}

/**
 * cpr3_regulator_config_vreg_ldo300() - configure the voltage and bypass state
 *		for the LDO300 regulator associated with a single CPR3
 *		regulator.
 *
 * @vreg:		Pointer to the CPR3 regulator
 * @new_volt:		New voltage in microvolts that VDD supply needs to
 *			end up at
 * @vdd_ceiling_volt:	Last known aggregated ceiling voltage in microvolts for
 *			the VDD supply
 *
 * This function performs all relevant LDO or BHS configurations for an LDO300
 * type regulator.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_regulator_config_vreg_ldo300(struct cpr3_regulator *vreg,
		int new_volt, int vdd_ceiling_volt)
{
	struct regulator *ldo_reg = vreg->ldo_regulator;
	struct cpr3_corner *corner;
	bool mode;
	int rc = 0;

	corner = &vreg->corner[vreg->current_corner];
	mode = corner->ldo_mode_allowed ? LDO_MODE : BHS_MODE;

	if (mode == LDO_MODE) {
		rc = regulator_set_voltage(ldo_reg, new_volt, vdd_ceiling_volt);
		if (rc) {
			cpr3_err(vreg, "regulator_set_voltage(ldo) == %d failed, rc=%d\n",
				 new_volt, rc);
			return rc;
		}
	}

	if (vreg->ldo_regulator_bypass != mode) {
		rc = regulator_allow_bypass(ldo_reg, mode);
		if (rc) {
			cpr3_err(vreg, "regulator_allow_bypass(%s) is failed, rc=%d\n",
				 mode == LDO_MODE ? "ldo" : "bhs", rc);
			return rc;
		}
		vreg->ldo_regulator_bypass = mode;
	}

	return rc;
}

/**
 * cpr3_regulator_config_vreg_ldo() - configure the voltage and bypass state for
 *		the LDO regulator associated with a single CPR3 regulator.
 *
 * @vreg:		Pointer to the CPR3 regulator
 * @vdd_floor_volt:	Last known aggregated floor voltage in microvolts for
 *			the VDD supply
 * @vdd_ceiling_volt:	Last known aggregated ceiling voltage in microvolts for
 *			the VDD supply
 * @new_volt:		New voltage in microvolts that VDD supply needs to
 *			end up at
 * @last_volt:		Last known voltage in microvolts for the VDD supply
 *
 * This function identifies the type of LDO regulator associated with a CPR3
 * regulator and invokes the LDO specific configuration functions.
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_regulator_config_vreg_ldo(struct cpr3_regulator *vreg,
			  int vdd_floor_volt, int vdd_ceiling_volt,
			  int new_volt, int last_volt)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	int ref_volt, rc;

	ref_volt = ctrl->use_hw_closed_loop ? vdd_floor_volt :
		new_volt;

	rc = cpr3_regulator_config_ldo_retention(vreg, ref_volt);
	if (rc)
		return rc;

	if (!vreg->vreg_enabled ||
		vreg->current_corner == CPR3_REGULATOR_CORNER_INVALID)
		return 0;

	switch (vreg->ldo_type) {
	case CPR3_LDO_KRYO:
		rc = cpr3_regulator_config_vreg_kryo_ldo(vreg, vdd_floor_volt,
				vdd_ceiling_volt, ref_volt, last_volt);
		if (rc)
			cpr3_err(vreg, "kryo ldo regulator config failed, rc=%d\n",
				rc);
		break;
	case CPR3_LDO300:
		rc = cpr3_regulator_config_vreg_ldo300(vreg, new_volt,
				vdd_ceiling_volt);
		if (rc)
			cpr3_err(vreg, "ldo300 regulator config failed, rc=%d\n",
				rc);
		break;
	default:
		cpr3_err(vreg, "invalid ldo regulator type = %d\n",
				vreg->ldo_type);
		rc = -EINVAL;
	}

	return rc;
}

/**
 * cpr3_regulator_config_ldo() - configure the voltage and bypass state for the
 *		LDO regulator associated with each CPR3 regulator of a CPR3
@@ -2529,6 +2667,12 @@ static int cpr3_regulator_scale_vdd_voltage(struct cpr3_controller *ctrl,
	int rc;

	if (new_volt < last_volt) {
		if (ctrl->support_ldo300_vreg) {
			rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
			if (rc)
				return rc;
		}

		/* Decreasing VDD voltage */
		rc = cpr3_regulator_config_ldo(ctrl, aggr_corner->floor_volt,
					       ctrl->aggr_corner.ceiling_volt,
@@ -2539,10 +2683,11 @@ static int cpr3_regulator_scale_vdd_voltage(struct cpr3_controller *ctrl,
			return rc;
		}

		if (!ctrl->support_ldo300_vreg) {
			rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
			if (rc)
				return rc;

		}
	} else {
		/* Increasing VDD voltage */
		if (ctrl->system_regulator) {
@@ -2903,6 +3048,8 @@ static void cpr3_regulator_aggregate_corners(struct cpr3_corner *aggr_corner,
	aggr_corner->mem_acc_volt
		= max(aggr_corner->mem_acc_volt, corner->mem_acc_volt);
	aggr_corner->irq_en |= corner->irq_en;
	aggr_corner->use_open_loop |= corner->use_open_loop;
	aggr_corner->ldo_mode_allowed |= corner->ldo_mode_allowed;

	if (aggr_quot) {
		aggr_corner->ro_mask &= corner->ro_mask;
@@ -3281,7 +3428,8 @@ static int _cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
	 * Only enable the CPR controller if it is possible to set more than
	 * one vdd-supply voltage.
	 */
	if (aggr_corner.ceiling_volt > aggr_corner.floor_volt)
	if (aggr_corner.ceiling_volt > aggr_corner.floor_volt &&
			!aggr_corner.use_open_loop)
		cpr3_ctrl_loop_enable(ctrl);

	ctrl->last_corner_was_closed_loop = ctrl->cpr_enabled;
+21 −0
Original line number Diff line number Diff line
@@ -141,6 +141,9 @@ struct cpr4_sdelta {
 * @use_open_loop:	Boolean indicating that open-loop (i.e CPR disabled) as
 *			opposed to closed-loop operation must be used for this
 *			corner on CPRh controllers.
 * @ldo_mode_allowed:	Boolean which indicates if LDO mode is allowed for this
 *			corner. This field is applicable for CPR4 controllers
 *			that manage LDO300 supply regulator.
 * @sdelta:		The CPR4 controller specific data for this corner. This
 *			field is applicable for CPR4 controllers.
 *
@@ -174,6 +177,7 @@ struct cpr3_corner {
	u32			irq_en;
	int			aging_derate;
	bool			use_open_loop;
	bool			ldo_mode_allowed;
	struct cpr4_sdelta	*sdelta;
};

@@ -192,6 +196,18 @@ struct cprh_corner_band {
	struct cpr4_sdelta	*sdelta;
};

/**
 * enum cpr3_ldo_type - Constants which define the LDO supply regulator
 *	types used to manage the subsystem component rail voltage.
 * %CPR3_LDO_KRYO:	Kryo LDO regulator used to sub-regulate the HMSS
 *			per-cluster voltage.
 * %CPR3_LDO300:	LDO regulator used to sub-regulate the GFX voltage.
 */
enum cpr3_ldo_type {
	CPR3_LDO_KRYO	= 0,
	CPR3_LDO300	= 1,
};

/**
 * struct cpr3_regulator - CPR3 logical regulator instance associated with a
 *			given CPR3 hardware thread
@@ -275,6 +291,7 @@ struct cprh_corner_band {
 *			participated in the last aggregation event
 * @debug_corner:	Index identifying voltage corner used for displaying
 *			corner configuration values in debugfs
 * @ldo_type:		LDO regulator type.
 * @ldo_min_headroom_volt: Minimum voltage difference in microvolts required
 *			between the VDD supply voltage and the LDO output in
 *			order for the LDO operate
@@ -358,6 +375,7 @@ struct cpr3_regulator {
	int			last_closed_loop_corner;
	bool			aggregated;
	int			debug_corner;
	enum cpr3_ldo_type	ldo_type;
	int			ldo_min_headroom_volt;
	int			ldo_max_headroom_volt;
	int			ldo_adjust_volt;
@@ -715,6 +733,8 @@ struct cpr3_panic_regs_info {
 * @panic_regs_info:	Array of panic registers information which provides the
 *			list of registers to dump when the device crashes.
 * @panic_notifier:	Notifier block registered to global panic notifier list.
 * @support_ldo300_vreg: Boolean value which indicates that this CPR controller
 *			manages an underlying LDO regulator of type LDO300.
 *
 * This structure contains both configuration and runtime state data.  The
 * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -815,6 +835,7 @@ struct cpr3_controller {
	u32			voltage_settling_time;
	struct cpr3_panic_regs_info *panic_regs_info;
	struct notifier_block	panic_notifier;
	bool			support_ldo300_vreg;
};

/* Used for rounding voltages to the closest physically available set point. */
+5 −5
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/kryo-regulator.h>
#include <linux/regulator/msm-ldo-regulator.h>

#include <soc/qcom/spm.h>

@@ -89,9 +89,9 @@ struct kryo_regulator {
	struct regulator_dev		*retention_rdev;
	struct regulator_desc		retention_desc;
	const char			*name;
	enum kryo_supply_mode		mode;
	enum kryo_supply_mode		retention_mode;
	enum kryo_supply_mode		pre_lpm_state_mode;
	enum msm_ldo_supply_mode	mode;
	enum msm_ldo_supply_mode	retention_mode;
	enum msm_ldo_supply_mode	pre_lpm_state_mode;
	void __iomem			*reg_base;
	void __iomem			*pm_apcc_base;
	struct dentry			*debugfs;
@@ -248,7 +248,7 @@ static int kryo_set_ldo_volt(struct kryo_regulator *kvreg, int volt)

/* Locks must be held by the caller */
static int kryo_configure_mode(struct kryo_regulator *kvreg,
				enum kryo_supply_mode mode)
				enum msm_ldo_supply_mode mode)
{
	u32 reg;
	int timeout = PWR_GATE_SWITCH_TIMEOUT_US;
+7 −7
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -11,22 +11,22 @@
 * GNU General Public License for more details.
 */

#ifndef __KRYO_REGULATOR_H__
#define __KRYO_REGULATOR_H__
#ifndef __MSM_LDO_REGULATOR_H__
#define __MSM_LDO_REGULATOR_H__

/**
 * enum kryo_supply_mode - supported operating modes by this regulator type.
 * enum msm_ldo_supply_mode - supported operating modes by this regulator type.
 * Use negative logic to ensure BHS mode is treated as the safe default by the
 * the regulator framework. This is necessary since LDO mode can only be enabled
 * when several constraints are satisfied. Consumers of this regulator are
 * expected to request changes in operating modes through the use of
 * regulator_allow_bypass() passing in the desired Kryo supply mode.
 * regulator_allow_bypass() passing in the desired LDO supply mode.
 * %BHS_MODE:	to select BHS as operating mode
 * %LDO_MODE:	to select LDO as operating mode
 */
enum kryo_supply_mode {
enum msm_ldo_supply_mode {
	BHS_MODE = false,
	LDO_MODE = true,
};

#endif /* __KRYO_REGULATOR_H__ */
#endif /* __MSM_LDO_REGULATOR_H__ */